package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.dto.InsertDTO;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.pro.product.pojo.dto.CostRecalculationDTO;
import com.xbongbong.pro.product.pojo.dto.ProductRecalculateDTO;
import com.xbongbong.pro.product.pojo.dto.ProductUpdateRecalculateDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.BatchFlowBillEntity;
import com.xbongbong.saas.domain.entity.BatchFlowBillUpdateEntity;
import com.xbongbong.saas.domain.entity.ContractProductEntity;
import com.xbongbong.saas.domain.entity.CostAdjustProductEntity;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ProductStockEntity;
import com.xbongbong.saas.domain.entity.ProductWarehouseEntity;
import com.xbongbong.saas.domain.entity.ReturnedPurchaseProductEntity;
import com.xbongbong.saas.domain.entity.StockFlowBillEntity;
import com.xbongbong.saas.domain.entity.StockFlowBillUpdateEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.CostAdjustEntityExt;
import com.xbongbong.saas.domain.entity.ext.InstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.OutstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.StockTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CostAdjustEnum;
import com.xbongbong.saas.enums.business.InstockEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.enums.subform.ProductStockSubFormEnum;
import com.xbongbong.saas.enums.subform.ProductWarehouseSubFormEnum;
import com.xbongbong.saas.help.BatchKeyHelp;
import com.xbongbong.saas.help.workflow.BatchFlowBillHelp;
import com.xbongbong.saas.help.workflow.StockFlowBillHelp;
import com.xbongbong.saas.model.BatchFlowBillModel;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.ContractProductModel;
import com.xbongbong.saas.model.CostAdjustProductModel;
import com.xbongbong.saas.model.InstockProductModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductStockModel;
import com.xbongbong.saas.model.ProductWarehouseModel;
import com.xbongbong.saas.model.ReturnedPurchaseProductModel;
import com.xbongbong.saas.model.StockFlowBillModel;
import com.xbongbong.saas.service.ContractService;
import com.xbongbong.saas.service.CostAdjustService;
import com.xbongbong.saas.service.CostRecalculationService;
import com.xbongbong.saas.service.ProductService;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.support.WriteRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getIntegerOrDefaultFromFormData;

/**
 * @author jiping.yang
 * @date 2021/12/2 18:48
 */
@Service("costRecalculationService")
public class CostRecalculationServiceImpl implements CostRecalculationService {

    private static final Logger LOG = LoggerFactory.getLogger(CostRecalculationServiceImpl.class);

    @Resource
    private StockFlowBillModel stockFlowBillModel;
    @Resource
    private BatchFlowBillModel batchFlowBillModel;
    @Resource
    private ProductModel productModel;
    @Resource
    private InstockProductModel instockProductModel;
    @Resource
    private ContractProductModel contractProductModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private ContractService contractService;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private ProductWarehouseModel productWarehouseModel;
    @Resource
    private ProductStockModel productStockModel;
    @Resource
    private ProductService productService;
    @Resource
    private CostAdjustService costAdjustService;
    @Resource
    private CostAdjustProductModel costAdjustProductModel;
    @Resource
    private ReturnedPurchaseProductModel returnedPurchaseProductModel;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private StockFlowBillHelp stockFlowBillHelp;
    @Resource
    private BatchFlowBillHelp batchFlowBillHelp;

    /**
     * 新建单据重算方法、先生成流水，后进行重算
     */
    @Override
    public void costRecalculationAdd(CostRecalculationDTO costRecalculationDTO) throws XbbException {
        if (Objects.equals(costRecalculationDTO.getMark() , BasicConstant.ONE)){
            //生成流水
            SaasFormSaveDTO saasFormSaveDTO = costRecalculationDTO.getSaasFormSaveDTO();
            stockFlowBillHelp.caculateStockModification4Save(saasFormSaveDTO.getCorpid(), saasFormSaveDTO.getBusinessType(), saasFormSaveDTO.getNewData(), saasFormSaveDTO.getNewPaasFormDataEntity());
            batchFlowBillHelp.batchFlowModification4Save(saasFormSaveDTO.getCorpid(), saasFormSaveDTO.getBusinessType(), saasFormSaveDTO.getNewData(), saasFormSaveDTO.getNewPaasFormDataEntity());
        }
        //开始重算
        costRecalculationAddRun(costRecalculationDTO);
    }

    /**
     * 删除单据重算方法、先删除流水，后进行重算
     */
    @Override
    public void costRecalculationDelete(CostRecalculationDTO costRecalculationDTO) throws XbbException {
        List<Long> outstockIdIn = costRecalculationDTO.getStockIdIn();
        List<Long> batchOutStockIdIn = costRecalculationDTO.getBatchOutStockIdIn();
        List<StockFlowBillUpdateEntity> stockFlowBillUpdateList = costRecalculationDTO.getStockFlowBillUpdateList();
        List<BatchFlowBillUpdateEntity> batchFlowBillUpdateEntityList = costRecalculationDTO.getBatchFlowBillUpdateEntityList();
        String corpid = costRecalculationDTO.getCorpid();
        Integer code = 0;
        if (Objects.equals(costRecalculationDTO.getType(), StockTypeEnum.IN_STOCK.getCode())){
            code = XbbRefTypeEnum.INSTOCK.getCode();
        }else if (Objects.equals(costRecalculationDTO.getType(), StockTypeEnum.OUT_STOCK.getCode())){
            code = XbbRefTypeEnum.OUTSTOCK.getCode();
        }if (Objects.equals(costRecalculationDTO.getType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            code = XbbRefTypeEnum.COST_ADJUST.getCode();
        }
        //生成流水
        stockFlowBillHelp.caculateStockModification4Delete(outstockIdIn, stockFlowBillUpdateList, code, corpid);
        batchFlowBillHelp.batchFlowModification4Delete(batchOutStockIdIn, batchFlowBillUpdateEntityList, code, corpid);
        //开始重算
        costRecalculationDeleteRun(costRecalculationDTO);
    }

    /**
     * 新增出入库单据重算方法
     * @param costRecalculationDTO
     * @throws XbbException
     */
    @Transactional(rollbackFor = Exception.class)
    public void costRecalculationAddRun(CostRecalculationDTO costRecalculationDTO) throws XbbException {
        String corpid = costRecalculationDTO.getCorpid();
        JSONObject data = costRecalculationDTO.getData();
        Long stockId = costRecalculationDTO.getStockId();
        Long date = data.getLong(InstockEnum.TIME.getAttr());
        JSONArray productArray = data.getJSONArray(InstockEnum.PRODUCT.getAttr());
        List<Long> stockProductId = new ArrayList<>();
        List<Long> batchProductId = new ArrayList<>();
        //获得计算map，按warehouseKey进行分组
        Map<String, List<StockFlowBillEntity>> stockFlowBillListMap = getStockFlowCalculateMap(productArray, stockProductId, batchProductId, costRecalculationDTO.getType(), costRecalculationDTO.getIsWorkFlow());
        //获得对比List，按最小粒度进行分组进行分组
        List<String> batchKeyList = getBatchKeyList(productArray, costRecalculationDTO.getType(), costRecalculationDTO.getIsWorkFlow());
        //获得批次流水与库存流水数据
        List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillModel.queryStockFlowbydateAndId(corpid, date, stockProductId);
        List<BatchFlowBillEntity> batchFlowBillEntityList = batchFlowBillModel.queryBatchFlowbydateAndId(corpid, date, batchProductId);
        //处理数据需要使用的map
        Map<String, BatchFlowBillEntity> batchFlowBillMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, BatchFlowBillEntity> productFlowBill = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, StockFlowBillEntity> stockFlowBillMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //将库存流水数据与批次流水数据按照ref_product_id + stockType为key，将数据存下来，方便后面获取进行计算
        batchFlowBillEntityList.forEach(batchFlowBillEntity -> {
            if(Objects.equals(batchFlowBillEntity.getBusinessType(), XbbRefTypeEnum.PRODUCTION_MATERIEL_OUTSTOCK.getCode())){
                BatchFlowBillEntity batchFlowBillExt = new BatchFlowBillEntity();
                BeanUtil.copyProperties(batchFlowBillEntity, batchFlowBillExt);
                productFlowBill.put(batchFlowBillEntity.getRefProductId() +"_"+ batchFlowBillEntity.getStockType(), batchFlowBillExt);
            }
            batchFlowBillMap.put(batchFlowBillEntity.getRefProductId() +"_"+ batchFlowBillEntity.getStockType(), batchFlowBillEntity);
        });
        stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
            if(Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.PRODUCTION_MATERIEL_OUTSTOCK.getCode())){
                StockFlowBillEntity stockFlowBillExt = new StockFlowBillEntity();
                BeanUtil.copyProperties(stockFlowBillEntity, stockFlowBillExt);
                stockFlowBillMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillExt);
            }
        });
        //删除插入单据之前不需要计算的流水
        removeStockFlowBill(stockFlowBillEntityList, batchFlowBillMap, stockId, stockFlowBillListMap, costRecalculationDTO.getMark());
        //处理销售出库流水和出库发货流水与退货入库流水的关联关系 入库流水->入库产品关联表->合同产品关联表->出库产品关联表->出库流水表
        Map<Long, Long> refundAndContract = getRefundAndContractAdd(stockFlowBillListMap, corpid);
        //处理领料出库流水和退料入库流水的关联关系 入库流水->入库产品表->出库产品表->出库流水
        Map<Long, Long> prckingInAndOut = getPrckingInAndOutAdd(stockFlowBillListMap, corpid);
        //处理采购入库和退货出库的关联关系 出库流水->出库产品关联表->采购退货产品关联表->入库产品关联表->入库流水
        Map<Long, Long> returnedAndInstock = getReturnedAndInstockAdd(stockFlowBillListMap, corpid);
        //储存计算信息map
        Map<String, ProductRecalculateDTO> productStockBatchMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, ProductRecalculateDTO> productstockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //需要更新的信息
        ProductUpdateRecalculateDTO productUpdateRecalculate = new ProductUpdateRecalculateDTO();
        Map<String, StockFlowBillEntity> stockFlowBillEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, BatchFlowBillEntity> batchFlowBillEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //开始重算
        for (String warehouseKey : stockFlowBillListMap.keySet()){
            List<StockFlowBillEntity> stockFlowBillList = stockFlowBillListMap.get(warehouseKey);
            //数量为1，代表是最后一条，不用处理。
            if (stockFlowBillList.size() <= 1){
                continue;
            }
            stockFlowBillList.forEach(stockFlowBillEntity -> {
                ProductRecalculateDTO productStockBatch = null;
                ProductRecalculateDTO productStock = null;
                //判断批次流水中是否有数据，有则代表开启了批次
                BatchFlowBillEntity batchFlowBill = batchFlowBillMap.get(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType());
                String batchKey=null;
                if (Objects.nonNull(batchFlowBill)){
                    batchKey = batchFlowBill.getBatchKey();
                }else {
                    batchKey = stockFlowBillEntity.getProductId() +"_"+ stockFlowBillEntity.getWarehouseId();
                }
                String stockKey = stockFlowBillEntity.getProductId() +"_"+ stockFlowBillEntity.getWarehouseId();
                //对有关联关系的单据进行处理
                BatchFlowBillEntity batchFlowBillEntityExt = new BatchFlowBillEntity();
                StockFlowBillEntity stockFlowBillEntityExt = new StockFlowBillEntity();
                BatchFlowBillEntity oldbatchFlowBillEntity = new BatchFlowBillEntity();
                StockFlowBillEntity oldStockFlowBillEntity = new StockFlowBillEntity();
                if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                    //销售退货入库
                    Long relevanceOutstockId = refundAndContract.get(stockFlowBillEntity.getId());
                    batchFlowBillEntityExt = batchFlowBillEntityMap.get(relevanceOutstockId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                    stockFlowBillEntityExt = stockFlowBillEntityMap.get(relevanceOutstockId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                }else if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                    //退料入库
                    Long outstockProductId = prckingInAndOut.get(stockFlowBillEntity.getId());
                    batchFlowBillEntityExt = batchFlowBillEntityMap.get(outstockProductId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                    stockFlowBillEntityExt = stockFlowBillEntityMap.get(outstockProductId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                    oldStockFlowBillEntity = stockFlowBillMap.get(outstockProductId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                    oldbatchFlowBillEntity = productFlowBill.get(outstockProductId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                }else if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                    //退货出库
                    Long instockProductId = returnedAndInstock.get(stockFlowBillEntity.getId());
                    batchFlowBillEntityExt = batchFlowBillEntityMap.get(instockProductId +"_"+ StockTypeEnum.IN_STOCK.getCode());
                    stockFlowBillEntityExt = stockFlowBillEntityMap.get(instockProductId +"_"+ StockTypeEnum.IN_STOCK.getCode());
                }
                //判断单据是否是需要进行重算的单据
                if (batchKeyList.contains(batchKey)){
                    //判断单据在不在库存流水集合里面，不在则代表是第一个单据
                    boolean isFirstData = false;
                    if (Objects.nonNull(batchFlowBill)){
                        isFirstData = productstockMap.containsKey(stockKey) && productStockBatchMap.containsKey(batchKey);
                    }else {
                        isFirstData = productstockMap.containsKey(stockKey);
                    }
                    if (isFirstData){
                        if (Objects.nonNull(batchFlowBill)){
                            productStockBatch = productStockBatchMap.get(batchKey);
                            //计算库存流水信息，用来更新库存流水
                            productStock = productstockMap.get(stockKey);
                            stockFlowCalculateByBatch(productStock, productStockBatch, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                            //计算批次流水信息，用来更新批次产品相关
                            batchFlowCalculate(productStockBatch, batchFlowBill, batchFlowBillEntityExt, oldbatchFlowBillEntity);
                            //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                            if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                //库存流水需要更新的数据
                                StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByBatch(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity, productStockBatch, batchFlowBill);
                                productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                                stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                            }
                            //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                            if (batchFlowBill.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                //批次流水需要更新的数据
                                BatchFlowBillEntity batchFlowBillEntitys = batchFlowBillCalculate(productStockBatch, batchFlowBill, batchFlowBillEntityExt, oldbatchFlowBillEntity );
                                productUpdateRecalculate.getBatchFlowBillEntityList().add(batchFlowBillEntitys);
                                batchFlowBillEntityMap.put(batchFlowBill.getRefProductId() +"_"+ batchFlowBill.getStockType(), batchFlowBillEntitys);
                            }
                        }else {
                            //计算库存流水信息，用来更新库存流水
                            productStock = productstockMap.get(stockKey);
                            stockFlowCalculate(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                            //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                            if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByStock(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                                productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                                stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                            }
                        }
                    }else {
                        //批次流水计算初始值信息
                        if (Objects.nonNull(batchFlowBill)){
                            productStockBatch = getBatchFlowCalculate(batchFlowBill);
                            //计算库存流水信息，用来更新库存流水
                            productStock = productstockMap.get(stockKey);
                            if (Objects.isNull(productStock)){
                                productStock = getStockFlowCalculate(stockFlowBillEntity);
                            }
                            stockFlowCalculateByBatch(productStock, productStockBatch, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                            //计算批次信息
                            batchFlowCalculate(productStockBatch, batchFlowBill, batchFlowBillEntityExt, oldbatchFlowBillEntity);
                            //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                            if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                //库存流水需要更新的数据
                                StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByBatch(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity, productStockBatch, batchFlowBill);
                                productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                                stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                            }
                            //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                            if (batchFlowBill.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                //批次流水需要更新的数据
                                BatchFlowBillEntity batchFlowBillEntitys = batchFlowBillCalculate(productStockBatch, batchFlowBill, batchFlowBillEntityExt, oldbatchFlowBillEntity );
                                productUpdateRecalculate.getBatchFlowBillEntityList().add(batchFlowBillEntitys);
                                batchFlowBillEntityMap.put(batchFlowBill.getRefProductId() +"_"+ batchFlowBill.getStockType(), batchFlowBillEntitys);
                            }
                        }else {
                            //库存流水计算初始值信息
                            productStock = getStockFlowCalculate(stockFlowBillEntity);
                            stockFlowCalculate(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                            //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                            if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByStock(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                                productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                                stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                            }
                        }
                    }
                }else {
                    if (Objects.nonNull(batchFlowBill)){
                        //计算库存流水信息，用来更新库存流水
                        productStock = productstockMap.get(stockKey);
                        stockFlowCalculateByBatchTwo(productStock,batchFlowBill);
                        //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                        if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                            //库存流水需要更新的数据
                            StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByNotBatch(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity, batchFlowBill);
                            productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                            stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                        }
                    }
                }
                //将每次处理完单据后的结余数量与成本记录下来，方便带入下一次数据的处理
                if(Objects.nonNull(productStockBatch)){
                    productStockBatchMap.put(batchKey,productStockBatch);
                }
                if(Objects.nonNull(productStock)){
                    productstockMap.put(stockKey,productStock);
                }
            });
        }
        //处理需要更新单据的数据
        updateDataRecalculate(productUpdateRecalculate, stockFlowBillEntityMap, batchFlowBillEntityMap, productstockMap, productStockBatchMap, corpid, productArray);
        //处理老数据成本问题
        updateOldDateByAdd(stockFlowBillListMap, batchFlowBillEntityList, productUpdateRecalculate);
        //更新库存流水，批次流水,出入库关联表，分仓表，批次表等信息
        updateData(productUpdateRecalculate, corpid);
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getProductWarehouseEntityList())){
            //获取产品分仓信息
            List<ProductEntityExt> productEntityExtList = findProductList(stockProductId, corpid);
            //更新产品信息
            int pageSize = 100;
            int totalCount = productEntityExtList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    productService.updateProductCostByid(productEntityExtList.subList(start * pageSize, totalCount), corpid);
                    break;
                }else {
                    productService.updateProductCostByid(productEntityExtList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getContractProductEntityList())){
            //更新合同信息
            updateContractDate(productUpdateRecalculate.getContractProductEntityList(), corpid);
        }
    }

    /**
     * 删除出入库单据重算方法
     * @param costRecalculationDTO
     * @throws XbbException
     */
    @Transactional(rollbackFor = Exception.class)
    public void costRecalculationDeleteRun(CostRecalculationDTO costRecalculationDTO) throws XbbException {
        String corpid = costRecalculationDTO.getCorpid();
        List<OutstockEntityExt> outstockList = costRecalculationDTO.getOutstockList();
        List<InstockEntityExt> instockList = costRecalculationDTO.getInstockList();
        List<OutstockProductEntity> outstockProductList = costRecalculationDTO.getOutstockProductList();
        List<InstockProductEntity> instockProductList = costRecalculationDTO.getInstockProductList();
        List<Long> stockIdIn = costRecalculationDTO.getStockIdIn();
        Integer type = costRecalculationDTO.getType();
        Map<Long, Integer> productDate = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long>  productIdList = new ArrayList<>();
        //获得每个产品对应的出入库的最早时间
        if (Objects.equals(costRecalculationDTO.getType(), StockTypeEnum.OUT_STOCK.getCode())){
            productDate = getProductDateByOutstock(outstockList);
            productIdList = getOutstockProductIdList(outstockProductList);
        }else if (Objects.equals(costRecalculationDTO.getType(), StockTypeEnum.IN_STOCK.getCode())){
            productDate = getProductDateByInstock(instockList);
            productIdList = getInstockProductIdList(instockProductList);
        }else if (Objects.equals(costRecalculationDTO.getType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            CostAdjustEntityExt costAdjustEntityExt = costAdjustService.getEntityById(stockIdIn.get(0) , corpid);
            productDate = getProductDateByCostAdjust(costAdjustEntityExt);
            JSONArray productArrayCost = costAdjustEntityExt.getData().getJSONArray(CostAdjustEnum.PRODUCT.getAttr());
            for (int i=0; i<productArrayCost.size(); i++){
                productIdList.add(productArrayCost.getLong(i));
            }
        }
        //获得库存流水时间轴
        List<StockFlowBillEntity> stockFlowBillEntityLists = queryStockFlowbydate(corpid, productDate);
        //将不需要参与计算的流水剔除
        Map<Long, List<StockFlowBillEntity>> stockFlowBillListMap = getStockMap(stockFlowBillEntityLists, productDate, stockIdIn, type);
        //获得批次流水时间轴，产品信息
        List<BatchFlowBillEntity> batchFlowBillEntityList = queryBatchFlowbydate(corpid, productDate);
        Map<String, BatchFlowBillEntity> productFlowBill = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, BatchFlowBillEntity> batchFlowBillMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        batchFlowBillEntityList.forEach(batchFlowBillEntity -> {
            if(Objects.equals(batchFlowBillEntity.getBusinessType(), XbbRefTypeEnum.PRODUCTION_MATERIEL_OUTSTOCK.getCode())){
                BatchFlowBillEntity batchFlowBillExt = new BatchFlowBillEntity();
                BeanUtil.copyProperties(batchFlowBillEntity, batchFlowBillExt);
                productFlowBill.put(batchFlowBillEntity.getRefProductId() +"_"+ batchFlowBillEntity.getStockType(), batchFlowBillExt);
            }
            batchFlowBillMap.put(batchFlowBillEntity.getRefProductId() +"_"+ batchFlowBillEntity.getStockType(), batchFlowBillEntity);
        });
        Map<Long, ProductEntityExt> productEntityMap = productModel.getProductMapByIdIn(corpid, productIdList, DelEnum.NORMAL.getDel());
        JSONArray productArray = new JSONArray();
        for (Long productId : productEntityMap.keySet()){
            ProductEntityExt productEntityExt = productEntityMap.get(productId);
            JSONObject data = productEntityExt.getData();
            data.put(ProductEnum.NAME.getAttr(), productEntityExt.getId());
            productArray.add(data);
        }
        Map<String, StockFlowBillEntity> stockFlowBillMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        stockFlowBillEntityLists.forEach(stockFlowBillEntity -> {
            if(Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.PRODUCTION_MATERIEL_OUTSTOCK.getCode())){
                StockFlowBillEntity stockFlowBillExt = new StockFlowBillEntity();
                BeanUtil.copyProperties(stockFlowBillEntity, stockFlowBillExt);
                stockFlowBillMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillExt);
            }
        });
        //处理销售出库流水和退货入库流水的关联关系 入库流水->入库产品关联表->合同产品关联表->出库产品关联表->出库流水表
        Map<Long, Long> refundAndContract = getRefundAndContractDelete(stockFlowBillListMap, corpid);
        //处理领料出库流水和退料入库流水的关联关系 入库流水->入库产品表->出库产品表->出库流水
        Map<Long, Long> prckingInAndOut = getPrckingInAndOutDelete(stockFlowBillListMap, corpid);
        //处理采购入库和退货出库的关联关系 出库流水->出库产品关联表->采购退货产品关联表->入库产品关联表->入库流水
        Map<Long, Long> returnedAndInstock = getReturnedAndInstockDelete(stockFlowBillListMap, corpid);
        //储存计算信息map
        Map<String, ProductRecalculateDTO> productStockBatchMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, ProductRecalculateDTO> productstockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //需要更新的信息
        ProductUpdateRecalculateDTO productUpdateRecalculate = new ProductUpdateRecalculateDTO();
        Map<String, StockFlowBillEntity> stockFlowBillEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, BatchFlowBillEntity> batchFlowBillEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(Long productId : stockFlowBillListMap.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(productId);
            //排除删除的出入库单关联的都是相同产品的情况
            Boolean allDelete = true;
            for (StockFlowBillEntity stockFlowBillEntity : stockFlowBillEntityList){
                if (Objects.equals(stockFlowBillEntity.getDel(), DelEnum.NORMAL.getDel())){
                    allDelete = false;
                    break;
                }
            }
            if (Objects.isNull(stockFlowBillEntityList) || stockFlowBillEntityList.size() <= 1 || allDelete){
                continue;
            }
            //判断产品是否开启批次管理
            JSONObject productData = productEntityMap.get(productId).getData();
            Integer enableBatchShelfLife = getIntegerOrDefaultFromFormData(productData, ProductEnum.ENABLE_BATCH_SHELF_LIFE.getAttr(), 0);
            //开始重算
            Map<Long, Long> finalRefundAndContract = refundAndContract;
            stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                String batchKey = null;
                BatchFlowBillEntity batchFlowBillEntity = null;
                //根据产品是否开启批次管理获取不同的key
                if (BasicConstant.ONE.equals(enableBatchShelfLife)){
                    batchFlowBillEntity = batchFlowBillMap.get(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType());
                    batchKey = batchFlowBillEntity.getBatchKey();
                }else if (BasicConstant.ZERO.equals(enableBatchShelfLife)){
                    batchKey = stockFlowBillEntity.getProductId() +"_"+ stockFlowBillEntity.getWarehouseId();
                }
                String stockKey = stockFlowBillEntity.getProductId() +"_"+ stockFlowBillEntity.getWarehouseId();
                ProductRecalculateDTO productStockBatch = null;
                ProductRecalculateDTO productStock = null;
                DelEnum delEnum = DelEnum.getByDel(stockFlowBillEntity.getDel());
                //对有关联关系的单据进行处理
                BatchFlowBillEntity batchFlowBillEntityExt = new BatchFlowBillEntity();
                StockFlowBillEntity stockFlowBillEntityExt = new StockFlowBillEntity();
                BatchFlowBillEntity oldbatchFlowBillEntity = new BatchFlowBillEntity();
                StockFlowBillEntity oldStockFlowBillEntity = new StockFlowBillEntity();
                if (Objects.equals(stockFlowBillEntity.getBusinessType() , XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                    Long relevanceOutstockId = refundAndContract.get(stockFlowBillEntity.getId());
                    batchFlowBillEntityExt = batchFlowBillEntityMap.get(relevanceOutstockId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                    stockFlowBillEntityExt = stockFlowBillEntityMap.get(relevanceOutstockId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                }else if (Objects.equals(stockFlowBillEntity.getBusinessType() , XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                    Long outstockProductId = prckingInAndOut.get(stockFlowBillEntity.getId());
                    batchFlowBillEntityExt = batchFlowBillEntityMap.get(outstockProductId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                    stockFlowBillEntityExt = stockFlowBillEntityMap.get(outstockProductId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                    oldStockFlowBillEntity = stockFlowBillMap.get(outstockProductId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                    oldbatchFlowBillEntity = productFlowBill.get(outstockProductId +"_"+ StockTypeEnum.OUT_STOCK.getCode());
                }else if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                    //退货出库
                    Long instockProductId = returnedAndInstock.get(stockFlowBillEntity.getId());
                    batchFlowBillEntityExt = batchFlowBillEntityMap.get(instockProductId +"_"+ StockTypeEnum.IN_STOCK.getCode());
                    stockFlowBillEntityExt = stockFlowBillEntityMap.get(instockProductId +"_"+ StockTypeEnum.IN_STOCK.getCode());
                }
                switch (delEnum){
                    case DELETE:
                        //判断需要删除的单据是否在集合中，不在便代表是新的数据轴，用来更新批次流水
                        if (!productStockBatchMap.containsKey(batchKey)) {
                            if (BasicConstant.ONE.equals(enableBatchShelfLife)){
                                //批次流水计算初始值信息
                                productStockBatch = getBatchFlowCalculate(batchFlowBillEntity);
                            }
                            //判断需要删除的单据是否在集合中，不在便代表是新的数据轴，用来更新库存流水
                            if (!productstockMap.containsKey(stockKey)) {
                                //库存流水计算初始值信息
                                productStock = getStockFlowCalculate(stockFlowBillEntity);
                            }
                        }
                        break;
                    case NORMAL:
                        //不需要删除的单据是否在集合中，不在便代表不需要处理，用来更新批次流水
                        if (productStockBatchMap.containsKey(batchKey)){
                            if (BasicConstant.ONE.equals(enableBatchShelfLife)){
                                productStockBatch = productStockBatchMap.get(batchKey);
                                productStock = productstockMap.get(stockKey);
                                //计算库存流水信息，用来更新库存流水
                                stockFlowCalculateByBatch(productStock, productStockBatch, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                                //计算批次流水信息，用来更新批次产品相关
                                batchFlowCalculate(productStockBatch, batchFlowBillEntity, batchFlowBillEntityExt, oldbatchFlowBillEntity);
                                //判断单据的出创建时间在不在上线前，上线后的数据才进行更新
                                if (batchFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                    //批次流水需要更新的数据
                                    BatchFlowBillEntity batchFlowBillEntitys = batchFlowBillCalculate(productStockBatch, batchFlowBillEntity , batchFlowBillEntityExt , oldbatchFlowBillEntity);
                                    productUpdateRecalculate.getBatchFlowBillEntityList().add(batchFlowBillEntitys);
                                    batchFlowBillEntityMap.put(batchFlowBillEntity.getRefProductId() +"_"+ batchFlowBillEntity.getStockType(), batchFlowBillEntitys);
                                }
                                //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                                if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                    //库存流水需要更新的数据
                                    StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByBatch(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity, productStockBatch, batchFlowBillEntity);
                                    productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                                    stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                                }
                            }else {
                                //计算库存流水信息，用来更新库存流水
                                productStock = productstockMap.get(stockKey);
                                stockFlowCalculateByBatch(productStock, productStockBatch, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                                //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                                if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                    //库存流水需要更新的数据
                                    StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByBatch(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity, productStockBatch, batchFlowBillEntity);
                                    productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                                    stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                                }
                            }
                        }else {
                            //不在批次流水集合里面的数据，也可能在库存流水集合里面
                            if (productstockMap.containsKey(stockKey)){
                                if (BasicConstant.ONE.equals(enableBatchShelfLife)){
                                    productStock = productstockMap.get(stockKey);
                                    //计算库存流水信息，用来更新库存流水
                                    stockFlowCalculateByBatchTwo(productStock, batchFlowBillEntity);
                                    //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                                    if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                        StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByNotBatch(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity, batchFlowBillEntity);
                                        productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                                        stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                                    }
                                }else {
                                    productStock = productstockMap.get(stockKey);
                                    //计算库存流水信息，用来更新库存流水
                                    stockFlowCalculate(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                                    //判断单据的创建时间在不在上线前，上线后的数据才进行更新
                                    if (stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                                        StockFlowBillEntity stockFlowBillEntitys = stockFlowBillCalculateByStock(productStock, stockFlowBillEntity, stockFlowBillEntityExt, oldStockFlowBillEntity);
                                        productUpdateRecalculate.getStockFlowBillEntityList().add(stockFlowBillEntitys);
                                        stockFlowBillEntityMap.put(stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType(), stockFlowBillEntitys);
                                    }
                                }
                            }
                        }
                        break;
                    default:
                        break;
                }
                //将每次处理完单据后的结余数量与成本记录下来，方便带入下一次数据的处理
                if(Objects.nonNull(productStockBatch)){
                    productStockBatchMap.put(batchKey,productStockBatch);
                }
                if(Objects.nonNull(productStock)){
                    productstockMap.put(stockKey,productStock);
                }
            });
        }
        //处理需要更新单据的数据
        updateDataRecalculate(productUpdateRecalculate, stockFlowBillEntityMap, batchFlowBillEntityMap, productstockMap, productStockBatchMap, corpid, productArray);
        //处理老数据分仓成本，批次成本问题
        updateOldDateByDelete(stockFlowBillListMap, batchFlowBillEntityList, productUpdateRecalculate);
        //更新库存流水，批次流水,出入库关联表，分仓表，批次表等信息
        updateData(productUpdateRecalculate, corpid);
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getProductWarehouseEntityList())){
            //获取产品分仓信息
            List<ProductEntityExt> productEntityExtList = findProductList(productIdList, corpid);
            //更新产品信息
            int pageSize = 100;
            int totalCount = productEntityExtList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    productService.updateProductCostByid(productEntityExtList.subList(start * pageSize, totalCount), corpid);
                    break;
                }else {
                    productService.updateProductCostByid(productEntityExtList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getContractProductEntityList())){
            //更新合同信息
            updateContractDate(productUpdateRecalculate.getContractProductEntityList(), corpid);
        }
    }

    /**
     * 获取每个产品最早的删除时间
     * @param outstockList
     */
    private Map<Long, Integer> getProductDateByOutstock(List<OutstockEntityExt> outstockList){
        Map<Long, Integer> productDate = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockEntityExt outstockEntityExt : outstockList) {
            Integer date = outstockEntityExt.getData().getInteger(OutstockEnum.TIME.getAttr());
            JSONArray productArray = outstockEntityExt.getData().getJSONArray(OutstockEnum.PRODUCT.getAttr());
            for (int i=0; i<productArray.size(); i++){
                Long productId = productArray.getLong(i);
                if (productDate.containsKey(productId)){
                    Integer oldDate = productDate.get(productId);
                    if (oldDate>date){
                        productDate.put(productId,date);
                    }
                }else {
                    productDate.put(productId,date);
                }
            }
        }
        return productDate;
    }

    /**
     * 获得每个产品需要重算的最早的出入库时间
     * @param instockList
     * @return
     */
    private Map<Long, Integer> getProductDateByInstock(List<InstockEntityExt> instockList){
        Map<Long, Integer> productDate = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (InstockEntityExt instockEntityExt : instockList) {
            Integer date = instockEntityExt.getData().getInteger(InstockEnum.TIME.getAttr());
            JSONArray productArray = instockEntityExt.getData().getJSONArray(InstockEnum.PRODUCT.getAttr());
            for (int i=0 ; i<productArray.size() ; i++){
                Long productId = productArray.getLong(i);
                if (productDate.containsKey(productId)){
                    Integer oldDate = productDate.get(productId);
                    if (oldDate>date){
                        productDate.put(productId,date);
                    }
                }else {
                    productDate.put(productId,date);
                }
            }
        }
        return productDate;
    }

    /**
     * 获得成本调整单产品需要开始重算的最早的时间
     * @param costAdjustEntity
     * @return
     */
    private Map<Long, Integer> getProductDateByCostAdjust(CostAdjustEntityExt costAdjustEntity){
        Map<Long, Integer> productDate = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Integer date = costAdjustEntity.getData().getInteger(CostAdjustEnum.ADJUST_TIME.getAttr());
            JSONArray productArray = costAdjustEntity.getData().getJSONArray(CostAdjustEnum.PRODUCT.getAttr());
            for (int i=0 ; i<productArray.size() ; i++){
                Long productId = productArray.getLong(i);
                if (productDate.containsKey(productId)){
                    Integer oldDate = productDate.get(productId);
                    if (oldDate>date){
                        productDate.put(productId,date);
                    }
                }else {
                    productDate.put(productId,date);
                }
            }
        return productDate;
    }

    /**
     *获得符合条件的库存流水数据
     */
    private List<StockFlowBillEntity> queryStockFlowbydate(String corpid, Map<Long, Integer> productDate){
        List<Long> productIdIn = new ArrayList<>();
        //获取最早的时间
        Integer date = 0;
        for (Long productId : productDate.keySet()){
            productIdIn.add(productId);
            Integer newDate = productDate.get(productId);
            if (Objects.equals(date, 0)){
                date = newDate;
            }else if (date >= newDate){
                date = newDate;
            }
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("productIdIn", productIdIn);
        param.put("date", date);
        List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillModel.queryStockFlowbydate(param);
        return stockFlowBillEntityList;
    }

    /**
     * 获得重算的完整时间轴，去除不需要重算的流水数据
     * @param stockFlowBillEntityList
     * @param productDate
     * @param stockIdIn
     * @param type
     * @return
     */
    private Map<Long, List<StockFlowBillEntity>> getStockMap(List<StockFlowBillEntity> stockFlowBillEntityList, Map<Long, Integer> productDate, List<Long> stockIdIn, Integer type){
        Map<Long, List<StockFlowBillEntity>> productFlowBill = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //兼容入库单，出库单，成本调整单id一致的情况
        List<String> stockIdAndTYpeList = new ArrayList<>();
        for(Long stockId : stockIdIn){
            String stockIdAndType = stockId +"_"+ type;
            stockIdAndTYpeList.add(stockIdAndType);
        }
        //将多余流水剔除
        stockFlowBillEntityList.removeIf(stockFlowBillEntity ->
                (Objects.equals(stockFlowBillEntity.getDel(), DelEnum.DELETE.getDel()) && !stockIdAndTYpeList.contains(stockFlowBillEntity.getRefId() +"_"+ stockFlowBillEntity.getStockType())) ||
                        stockFlowBillEntity.getDate() < productDate.get(stockFlowBillEntity.getProductId())
        );
        //按productid给流水分类，方便后续的处理
        for(Long productId : productDate.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityExt = new ArrayList<>();
            stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                if (stockFlowBillEntity.getProductId().equals(productId)){
                    stockFlowBillEntityExt.add(stockFlowBillEntity);
                }
            });
            productFlowBill.put(productId,stockFlowBillEntityExt);
        }
        //去除不需要参与计算的流水
        for(Long productId : productFlowBill.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityLists = productFlowBill.get(productId);
            Iterator<StockFlowBillEntity> iterator = stockFlowBillEntityLists.iterator();
            while (iterator.hasNext()){
                StockFlowBillEntity stockFlowBillEntity = iterator.next();
                if (stockFlowBillEntity.getDel().equals(DelEnum.NORMAL.getDel())){
                    iterator.remove();
                }else if (stockFlowBillEntity.getDel().equals(DelEnum.DELETE.getDel())){
                    break;
                }
            }
        }
        return productFlowBill;
    }

    /**
     * 查询批次流水信息
     * @param corpid
     * @param productDate
     * @return
     */
    private List<BatchFlowBillEntity> queryBatchFlowbydate(String corpid, Map<Long, Integer> productDate){
        List<Long> productIdIn = new ArrayList<>();
        //获取最早的时间
        Integer date = 0;
        for (Long productId : productDate.keySet()){
            productIdIn.add(productId);
            Integer newDate = productDate.get(productId);
            if (Objects.equals(date, 0)){
                date = newDate;
            }else if (date >= newDate){
                date = newDate;
            }
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("productIdIn", productIdIn);
        param.put("date", date);
        List<BatchFlowBillEntity> batchFlowBillEntityList = batchFlowBillModel.queryBatchFlowbydate(param);
        return batchFlowBillEntityList;
    }

    private List<Long> getOutstockProductIdList(List<OutstockProductEntity> outstockProductList){
        List<Long> productIdList = new ArrayList<>();
        for (OutstockProductEntity entity : outstockProductList) {
            productIdList.add(entity.getProductId());
        }
        return productIdList;
    }

    private List<Long> getInstockProductIdList(List<InstockProductEntity> InstockProductList){
        List<Long> productIdList = new ArrayList<>();
        for (InstockProductEntity entity : InstockProductList) {
            productIdList.add(entity.getProductId());
        }
        return productIdList;
    }

    /**
     * 获取销售退货入库产品与销售出库产品的对应关系
     * @author jiping.yang
     * @date 2021/11/25 22:40
     */
    private Map<Long, Long> findRefundkProductandContract(Map<Long, Long> stockAndRefund, String corpid){
        Map<Long, Long> instockFlowAndContractProduct = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> instockFlowAndOutstockProduct = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> instockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> contractProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //获取入库产品关联表数据
        List<InstockProductEntity> instockProductEntityList = instockProductModel.findRefundkProductandContract(stockAndRefund , corpid);
        instockProductEntityList.forEach(instockProductEntity -> {
            instockProductMap.put(instockProductEntity.getId(), instockProductEntity.getRefProductId());
        });
        //将退货入库流水id与合同产品关联id对应信息建立
        for (Long instockFlowId : stockAndRefund.keySet()){
            Long instockProductId = stockAndRefund.get(instockFlowId);
            Long contractProductId = instockProductMap.get(instockProductId);
            instockFlowAndContractProduct.put(instockFlowId , contractProductId);
        }
        //获得合同产品关联表数据
        List<ContractProductEntity> contractProductEntityList = contractProductModel.getInstockProductAndContractProdcut(instockFlowAndContractProduct,corpid);
        contractProductEntityList.forEach(contractProductEntity -> {
            contractProductMap.put(contractProductEntity.getId(), contractProductEntity.getRefProductId());
        });
        //将退货入库流水id与出库产品关联id对应信息建立
        for (Long instockFlowId : instockFlowAndContractProduct.keySet()){
            Long contractProductId = instockFlowAndContractProduct.get(instockFlowId);
            Long outstockProductId = contractProductMap.get(contractProductId);
            instockFlowAndOutstockProduct.put(instockFlowId, outstockProductId);
        }
        return instockFlowAndOutstockProduct;
    }

    /**
     * 获取采购退货出库产品与采购入库产品的对应关系
     * @author jiping.yang
     * @date 2021/11/25 22:40
     */
    private Map<Long, Long> findReturnedAndInstock(Map<Long, Long> stockAndRefund, String corpid){
        Map<Long, Long> outstockFlowAndRefurned = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> outstockFlowAndIdstockProduct = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> returnedProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> outstockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> outstockProductIdIn = new ArrayList<>();
        //获取出库产品关联表数据
        for (Long outstockProductId : stockAndRefund.keySet()){
            outstockProductIdIn.add(stockAndRefund.get(outstockProductId));
        }
        List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.getOutstockProductById(outstockProductIdIn, corpid);
        outstockProductEntityList.forEach(outstockProductEntity -> {
            outstockProductMap.put(outstockProductEntity.getId(), outstockProductEntity.getRefProductId());
        });
        //将退货出库流水id与退货产品关联id对应信息建立
        for (Long outstockProductId : stockAndRefund.keySet()){
            Long refProductId = stockAndRefund.get(outstockProductId);
            Long returnedpurchaseId = outstockProductMap.get(refProductId);
            outstockFlowAndRefurned.put(outstockProductId , returnedpurchaseId);
        }
        //获得采购退货产品关联表数据
        List<ReturnedPurchaseProductEntity> returnedPurchaseProductList = returnedPurchaseProductModel.getReturnedPurchaseProductById(outstockFlowAndRefurned, corpid);
        returnedPurchaseProductList.forEach(returnedPurchaseProductEntity -> {
            returnedProductMap.put(returnedPurchaseProductEntity.getId(), returnedPurchaseProductEntity.getRefProductId());
        });
        //将采购退货出库流水id与入库产品关联id对应信息建立
        for (Long outstockPurchaseId : outstockFlowAndRefurned.keySet()){
            Long returnedpurchaseId = outstockFlowAndRefurned.get(outstockPurchaseId);
            Long inProductId = returnedProductMap.get(returnedpurchaseId);
            outstockFlowAndIdstockProduct.put(outstockPurchaseId, inProductId);
        }
        return outstockFlowAndIdstockProduct;
    }

    /**
     * 获得产品最新的分仓信息
     * @param prodcutIdList
     * @param corpid
     * @return
     */
    private List<ProductEntityExt> findProductList(List<Long> prodcutIdList , String corpid){
        List<ProductEntityExt> productEntityExtList = new ArrayList<>();
        List<ProductWarehouseEntity> productWarehouseEntityList = productWarehouseModel.findProductWarehouse(prodcutIdList , corpid);
        productWarehouseEntityList.forEach(productWarehouseEntity -> {
            ProductEntityExt productEntityExt = new ProductEntityExt();
            productEntityExt.setId(productWarehouseEntity.getProductId());
            productEntityExt.setNum(productWarehouseEntity.getNum());
            productEntityExt.setTotalCost(productWarehouseEntity.getTotalCost());
            productEntityExt.setUpdateTime(DateTimeUtil.getInt());
            if (Objects.equals(productWarehouseEntity.getNum().compareTo(0.00) ,0)){
                productEntityExt.setCost(productWarehouseEntity.getCost());
            }else {
                productEntityExt.setCost(Arith.div(productWarehouseEntity.getTotalCost() , productWarehouseEntity.getNum()));
            }
            productEntityExtList.add(productEntityExt);
        });
        return productEntityExtList;
    }

    /**
     * 删除插入单据之前不需要计算的多余的流水
     * @param stockFlowBillEntityList
     * @param batchFlowBillMap
     * @param stockId
     * @param stockFlowBillListMap
     */
    private void removeStockFlowBill(List<StockFlowBillEntity> stockFlowBillEntityList , Map<String , BatchFlowBillEntity> batchFlowBillMap , Long stockId , Map<String , List<StockFlowBillEntity>> stockFlowBillListMap, Integer mark){
        stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
            String warehouseKey = stockFlowBillEntity.getProductId() + "_" + stockFlowBillEntity.getWarehouseId();
            if (stockFlowBillListMap.containsKey(warehouseKey)){
                List<StockFlowBillEntity> stockFlowBillEntities = stockFlowBillListMap.get(warehouseKey);
                stockFlowBillEntities.add(stockFlowBillEntity);
                stockFlowBillListMap.put(warehouseKey , stockFlowBillEntities);
            }
        });
        if (!Objects.equals(mark, 3)){
            for(String warehouseKey : stockFlowBillListMap.keySet()) {
                List<StockFlowBillEntity> stockFlowBillEntities = stockFlowBillListMap.get(warehouseKey);
                Iterator<StockFlowBillEntity> iterator = stockFlowBillEntities.iterator();
                while (iterator.hasNext()) {
                    StockFlowBillEntity stockFlowBillEntity = iterator.next();
                    if (!Objects.equals(stockFlowBillEntity.getRefId(), stockId)) {
                        iterator.remove();
                    } else if (Objects.equals(stockFlowBillEntity.getRefId(), stockId)) {
                        break;
                    }
                }
            }
        }
    }

    /**
     * 获取流水中类型为销售退货入库的流水
     * @param stockFlowBillListMap
     * @param corpid
     * @return
     */
    private Map<Long, Long> getRefundAndContractDelete(Map<Long , List<StockFlowBillEntity>> stockFlowBillListMap , String corpid){
        Map<Long, Long> stockAndRefund = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(Long productId : stockFlowBillListMap.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(productId);
            stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                if (Objects.equals(stockFlowBillEntity.getBusinessType() , XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                    stockAndRefund.put(stockFlowBillEntity.getId() , stockFlowBillEntity.getRefProductId());
                }
            });
        }
        Map<Long , Long> refundAndContract = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(!stockAndRefund.isEmpty()){
            //集合不为空，则需要将上下游关系建立
            refundAndContract = findRefundkProductandContract(stockAndRefund , corpid);
        }
        return refundAndContract;
    }

    /**
     * 获取流水中类型为销售退货入库的流水
     * @param stockFlowBillListMap
     * @param corpid
     * @return
     */
    private Map<Long, Long> getRefundAndContractAdd(Map<String, List<StockFlowBillEntity>> stockFlowBillListMap, String corpid){
        Map<Long, Long> stockAndRefund = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(String warehouseKey : stockFlowBillListMap.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(warehouseKey);
            stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                    stockAndRefund.put(stockFlowBillEntity.getId(), stockFlowBillEntity.getRefProductId());
                }
            });
        }
        Map<Long, Long> refundAndContract = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(!stockAndRefund.isEmpty()){
            //集合不为空，则需要将上下游关系建立
            refundAndContract = findRefundkProductandContract(stockAndRefund , corpid);
        }
        return refundAndContract;
    }

    /**
     * 获取流水中类型为采购退货的流水
     * @param stockFlowBillListMap
     * @param corpid
     * @return
     */
    private Map<Long, Long> getReturnedAndInstockAdd(Map<String, List<StockFlowBillEntity>> stockFlowBillListMap, String corpid){
        Map<Long, Long> stockAndReturned = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(String warehouseKey : stockFlowBillListMap.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(warehouseKey);
            stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                    stockAndReturned.put(stockFlowBillEntity.getId(), stockFlowBillEntity.getRefProductId());
                }
            });
        }
        Map<Long, Long> returnedAndInstock = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(!stockAndReturned.isEmpty()){
            //集合不为空，则需要将上下游关系建立
            returnedAndInstock = findReturnedAndInstock(stockAndReturned , corpid);
        }
        return returnedAndInstock;
    }

    /**
     * 获取流水中类型为采购退货的流水
     * @param stockFlowBillListMap
     * @param corpid
     * @return
     */
    private Map<Long, Long> getReturnedAndInstockDelete(Map<Long, List<StockFlowBillEntity>> stockFlowBillListMap, String corpid){
        Map<Long, Long> stockAndReturned = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(Long batchKey : stockFlowBillListMap.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(batchKey);
            stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                    stockAndReturned.put(stockFlowBillEntity.getId(), stockFlowBillEntity.getRefProductId());
                }
            });
        }
        Map<Long, Long> returnedAndInstock = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(!stockAndReturned.isEmpty()){
            //集合不为空，则需要将上下游关系建立
            returnedAndInstock = findReturnedAndInstock(stockAndReturned , corpid);
        }
        return returnedAndInstock;
    }

    /**
     * 获取流水中为领料退货入库的流水
     * @param stockFlowBillListMap
     * @param corpid
     * @return
     */
    private Map<Long, Long> getPrckingInAndOutDelete(Map<Long, List<StockFlowBillEntity>> stockFlowBillListMap, String corpid){
        Map<Long, Long> stockAndPrcking = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(Long batchKey : stockFlowBillListMap.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(batchKey);
            stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                    stockAndPrcking.put(stockFlowBillEntity.getId(), stockFlowBillEntity.getRefProductId());
                }
            });
        }
        Map<Long, Long> prckingInAndOut = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> instockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(!stockAndPrcking.isEmpty()){
            //获取入库产品关联表数据
            List<InstockProductEntity> instockProductEntityList = instockProductModel.findRefundkProductandContract(stockAndPrcking , corpid);
            instockProductEntityList.forEach(instockProductEntity -> {
                instockProductMap.put(instockProductEntity.getId(), instockProductEntity.getRefProductId());
            });
            //将退料入库流水id与领料出库关联产品id对应信息建立
            for (Long instockFlowId : stockAndPrcking.keySet()){
                Long instockProductId = stockAndPrcking.get(instockFlowId);
                Long outstockProductId = instockProductMap.get(instockProductId);
                prckingInAndOut.put(instockFlowId, outstockProductId);
            }
        }
        return prckingInAndOut;
    }

    /**
     * 获取流水中为领料退货入库的流水
     * @param stockFlowBillListMap
     * @param corpid
     * @return
     */
    private Map<Long, Long> getPrckingInAndOutAdd(Map<String, List<StockFlowBillEntity>> stockFlowBillListMap, String corpid){
        Map<Long, Long> stockAndPrcking = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(String warehouseKey : stockFlowBillListMap.keySet()){
            List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(warehouseKey);
            stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                    stockAndPrcking.put(stockFlowBillEntity.getId(), stockFlowBillEntity.getRefProductId());
                }
            });
        }
        Map<Long, Long> prckingInAndOut = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> instockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(!stockAndPrcking.isEmpty()){
            //获取入库产品关联表数据
            List<InstockProductEntity> instockProductEntityList = instockProductModel.findRefundkProductandContract(stockAndPrcking , corpid);
            instockProductEntityList.forEach(instockProductEntity -> {
                instockProductMap.put(instockProductEntity.getId(), instockProductEntity.getRefProductId());
            });
            //将退料入库流水id与领料出库关联产品id对应信息建立
            for (Long instockFlowId : stockAndPrcking.keySet()){
                Long instockProductId = stockAndPrcking.get(instockFlowId);
                Long outstockProductId = instockProductMap.get(instockProductId);
                prckingInAndOut.put(instockFlowId, outstockProductId);
            }
        }
        return prckingInAndOut;
    }

    /**
     * 批次流水计算初始值
     * @param batchFlowBill
     * @return
     */
    private ProductRecalculateDTO getBatchFlowCalculate(BatchFlowBillEntity batchFlowBill){
        ProductRecalculateDTO productBatch = new ProductRecalculateDTO();
        productBatch.setProductId(batchFlowBill.getProductId());
        productBatch.setWarehouseId(batchFlowBill.getWarehouseId());
        productBatch.setBatchKey(batchFlowBill.getBatchKey());
        if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.ORI_STOCK.getCode())) {
            productBatch.setNum(Arith.sub(batchFlowBill.getRemainingStock(), batchFlowBill.getNum()));
            productBatch.setCost(Arith.sub(batchFlowBill.getRemainingCost(), Arith.mul(batchFlowBill.getProductCost() , batchFlowBill.getNum())));
        } else if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.OUT_STOCK.getCode())) {
            productBatch.setNum(Arith.add(batchFlowBill.getRemainingStock(), batchFlowBill.getNum()));
            productBatch.setCost(Arith.add(batchFlowBill.getRemainingCost(), Arith.mul(batchFlowBill.getProductCost() , batchFlowBill.getNum())));
        } else if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())) {
            productBatch.setNum(batchFlowBill.getRemainingStock());
            productBatch.setCost(Arith.sub(batchFlowBill.getRemainingCost(), batchFlowBill.getProductCost()));
        }
        return productBatch;
    }

    /**
     * 库存流水计算初始值
     * @param stockFlowBill
     * @return
     */
    private ProductRecalculateDTO getStockFlowCalculate(StockFlowBillEntity stockFlowBill){
        ProductRecalculateDTO productStock = new ProductRecalculateDTO();
        productStock.setProductId(stockFlowBill.getProductId());
        productStock.setWarehouseId(stockFlowBill.getWarehouseId());
        productStock.setWarehouseKey(stockFlowBill.getWarehouseKey());
        if (Objects.equals(stockFlowBill.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(stockFlowBill.getStockType(), StockTypeEnum.ORI_STOCK.getCode())) {
            productStock.setNum(Arith.sub(stockFlowBill.getRemainingStock(), stockFlowBill.getNum()));
            productStock.setCost(Arith.sub(stockFlowBill.getRemainingCost(), Arith.mul(stockFlowBill.getProductCost() , stockFlowBill.getNum())));
        } else if (Objects.equals(stockFlowBill.getStockType(), StockTypeEnum.OUT_STOCK.getCode())) {
            productStock.setNum(Arith.add(stockFlowBill.getRemainingStock(), stockFlowBill.getNum()));
            productStock.setCost(Arith.add(stockFlowBill.getRemainingCost(), Arith.mul(stockFlowBill.getProductCost() , stockFlowBill.getNum())));
        } else if (Objects.equals(stockFlowBill.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())) {
            productStock.setNum(stockFlowBill.getRemainingStock());
            productStock.setCost(Arith.sub(stockFlowBill.getRemainingCost(), stockFlowBill.getProductCost()));
        }
        return productStock;
    }


    /**
     * 计算批次流水信息，用来更新批次产品相关
     * @param
     */
    private void batchFlowCalculate(ProductRecalculateDTO finalProductBatch, BatchFlowBillEntity batchFlowBill, BatchFlowBillEntity batchFlowBillEntityExt, BatchFlowBillEntity oldbatchFlowBillEntity){
        if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.ORI_STOCK.getCode())){
            finalProductBatch.setNum(Arith.add(finalProductBatch.getNum(), batchFlowBill.getNum()));
            if (Objects.equals(batchFlowBill.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                if (Objects.nonNull(batchFlowBillEntityExt)){
                    finalProductBatch.setCost(Arith.add(finalProductBatch.getCost(), Arith.mul(batchFlowBillEntityExt.getProductCost(), batchFlowBill.getNum())));
                }else {
                    finalProductBatch.setCost(Arith.add(finalProductBatch.getCost(), Arith.mul(batchFlowBill.getProductCost(), batchFlowBill.getNum())));
                }
            }else if (Objects.equals(batchFlowBill.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                if (Objects.nonNull(batchFlowBillEntityExt)){
                    if (Objects.equals(oldbatchFlowBillEntity.getProductCost().compareTo(batchFlowBill.getProductCost()) ,0)){
                        finalProductBatch.setCost(Arith.add(finalProductBatch.getCost(), Arith.mul(batchFlowBillEntityExt.getProductCost(), batchFlowBill.getNum())));
                    }else {
                        finalProductBatch.setCost(Arith.add(finalProductBatch.getCost(), Arith.mul(batchFlowBill.getProductCost(), batchFlowBill.getNum())));
                    }
                }else {
                    finalProductBatch.setCost(Arith.add(finalProductBatch.getCost(), Arith.mul(batchFlowBill.getProductCost(), batchFlowBill.getNum())));
                }
            } else {
                finalProductBatch.setCost(Arith.add(finalProductBatch.getCost(), Arith.mul(batchFlowBill.getProductCost(), batchFlowBill.getNum())));
            }
        }else if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
            Double num = Arith.sub(finalProductBatch.getNum(), batchFlowBill.getNum());
            if (Objects.equals(batchFlowBill.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                finalProductBatch.setCost(Arith.sub(finalProductBatch.getCost(), Arith.mul(batchFlowBill.getProductCost(), batchFlowBill.getNum())));
            } else {
                double singleProductStock;
                if (finalProductBatch.getNum() <=0 ){
                    singleProductStock = BasicConstant.ZERO_DOUBLE;
                }else {
                    singleProductStock = Arith.div(finalProductBatch.getCost(), finalProductBatch.getNum());
                }
                Double cost = Arith.sub(finalProductBatch.getCost(), Arith.mul(singleProductStock , batchFlowBill.getNum()));
                //排除数量为0时精度的影响
                if (Objects.equals(num.compareTo(0.00), 0)){
                    cost = BasicConstant.ZERO_DOUBLE;
                }
                if (Objects.equals(cost.compareTo(0.00), 0) && batchFlowBill.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                    batchFlowBill.setProductCost(singleProductStock);
                }
                finalProductBatch.setCost(cost);
            }
            finalProductBatch.setNum(num);
        }else if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            finalProductBatch.setNum(finalProductBatch.getNum());
            finalProductBatch.setCost(Arith.add(finalProductBatch.getCost(), batchFlowBill.getProductCost()));
        }
    }

    /**
     * 批次流水需要更新的数据
     * @param
     */
    private BatchFlowBillEntity batchFlowBillCalculate(ProductRecalculateDTO finalProductBatch, BatchFlowBillEntity batchFlowBill, BatchFlowBillEntity batchFlowBillEntityExt, BatchFlowBillEntity oldbatchFlowBillEntity){
        BatchFlowBillEntity batchFlowBillEntity = new BatchFlowBillEntity();
        batchFlowBillEntity.setId(batchFlowBill.getId());
        batchFlowBillEntity.setNum(batchFlowBill.getNum());
        batchFlowBillEntity.setBusinessType(batchFlowBill.getBusinessType());
        batchFlowBillEntity.setBatchKey(batchFlowBill.getBatchKey());
        if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(batchFlowBill.getStockType() , StockTypeEnum.ORI_STOCK.getCode())){
            if (Objects.equals(batchFlowBill.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                if (Objects.nonNull(batchFlowBillEntityExt)){
                    batchFlowBillEntity.setProductCost(batchFlowBillEntityExt.getProductCost());
                }else {
                    batchFlowBillEntity.setProductCost(batchFlowBill.getProductCost());
                }
            }else if (Objects.equals(batchFlowBill.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                if (Objects.nonNull(batchFlowBillEntityExt)){
                    if (Objects.equals(oldbatchFlowBillEntity.getProductCost().compareTo(batchFlowBill.getProductCost()),0)){
                        batchFlowBillEntity.setProductCost(batchFlowBillEntityExt.getProductCost());
                    }else {
                        batchFlowBillEntity.setProductCost(batchFlowBill.getProductCost());
                    }
                }else {
                    batchFlowBillEntity.setProductCost(batchFlowBill.getProductCost());
                }
            }else {
                batchFlowBillEntity.setProductCost(batchFlowBill.getProductCost());
            }
        }else if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
            if (Objects.equals(batchFlowBill.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                batchFlowBillEntity.setProductCost(batchFlowBill.getProductCost());
            }else {
                if (Objects.equals(finalProductBatch.getNum().compareTo(0.00) ,0)){
                    if (Objects.equals(finalProductBatch.getCost().compareTo(0.00), 0)){
                        batchFlowBillEntity.setProductCost(batchFlowBill.getProductCost());
                    }else {
                        batchFlowBillEntity.setProductCost(0.00);
                    }
                }else if (finalProductBatch.getNum() < 0 && batchFlowBill.getRemainingCost() <= 0){
                    batchFlowBillEntity.setProductCost(0.00);
                }else {
                    batchFlowBillEntity.setProductCost(Arith.div(finalProductBatch.getCost(), finalProductBatch.getNum()));
                }
            }
        }else if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            batchFlowBillEntity.setProductCost(batchFlowBill.getProductCost());
        }
        batchFlowBillEntity.setRemainingStock(finalProductBatch.getNum());
        batchFlowBillEntity.setRemainingCost(finalProductBatch.getCost());
        return batchFlowBillEntity;
    }

    /**
     * 计算库存流水信息，用来更新库存产品相关
     * @param
     */
    private void stockFlowCalculate(ProductRecalculateDTO finalProductStock, StockFlowBillEntity stockFlowBillEntity, StockFlowBillEntity stockFlowBillEntityExt, StockFlowBillEntity oldStockFlowBillEntity){
        if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ORI_STOCK.getCode())){
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntityExt.getProductCost(), stockFlowBillEntity.getNum())));
                }else {
                    finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
                }
            }else if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    if (Objects.equals(oldStockFlowBillEntity.getProductCost().compareTo(stockFlowBillEntity.getProductCost()), 0)){
                        finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntityExt.getProductCost(), stockFlowBillEntity.getNum())));
                    }else {
                        finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
                    }
                }else {
                    finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
                }
            }else {
                finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
            }
            finalProductStock.setNum(Arith.add(finalProductStock.getNum(), stockFlowBillEntity.getNum()));
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
            Double num = Arith.sub(finalProductStock.getNum(), stockFlowBillEntity.getNum());
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                finalProductStock.setCost(Arith.sub(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
            }else {
                double singleProductStock;
                if (finalProductStock.getNum() <= 0){
                    singleProductStock = BasicConstant.ZERO_DOUBLE;
                }else {
                    singleProductStock = Arith.div(finalProductStock.getCost(), finalProductStock.getNum());
                }
                Double cost = Arith.sub(finalProductStock.getCost(), Arith.mul(singleProductStock, stockFlowBillEntity.getNum()));
                //排除数量为0时精度的影响
                if (Objects.equals(num.compareTo(0.00) ,0)){
                    cost = BasicConstant.ZERO_DOUBLE;
                }
                if (Objects.equals(cost.compareTo(0.00) ,0) && stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                    stockFlowBillEntity.setProductCost(singleProductStock);
                }
                finalProductStock.setCost(cost);
            }
            finalProductStock.setNum(num);
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            finalProductStock.setCost(Arith.add(finalProductStock.getCost(), stockFlowBillEntity.getProductCost()));
        }
    }

    /**
     * 计算库存流水信息，用来更新库存产品相关(有批次)
     * @param
     */
    private void stockFlowCalculateByBatch(ProductRecalculateDTO finalProductStock, ProductRecalculateDTO finalProductBatch, StockFlowBillEntity stockFlowBillEntity, StockFlowBillEntity stockFlowBillEntityExt, StockFlowBillEntity oldStockFlowBillEntity){
        if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ORI_STOCK.getCode())){
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntityExt.getProductCost(), stockFlowBillEntity.getNum())));
                }else {
                    finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
                }
            }else if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    if (Objects.equals(oldStockFlowBillEntity.getProductCost().compareTo(stockFlowBillEntity.getProductCost()), 0)){
                        finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntityExt.getProductCost(), stockFlowBillEntity.getNum())));
                    }else {
                        finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
                    }
                }else {
                    finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
                }
            }else {
                finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
            }
            finalProductStock.setNum(Arith.add(finalProductStock.getNum(), stockFlowBillEntity.getNum()));
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
            Double num = Arith.sub(finalProductStock.getNum(), stockFlowBillEntity.getNum());
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                finalProductStock.setCost(Arith.sub(finalProductStock.getCost(), Arith.mul(stockFlowBillEntity.getProductCost(), stockFlowBillEntity.getNum())));
            }else {
                double singleProductStock;
                if (finalProductBatch.getNum() <= 0){
                    singleProductStock = BasicConstant.ZERO_DOUBLE;
                }else {
                    singleProductStock = Arith.div(finalProductBatch.getCost(), finalProductBatch.getNum());
                }
                Double cost = Arith.sub(finalProductStock.getCost(), Arith.mul(singleProductStock, stockFlowBillEntity.getNum()));
                //排除数量为0时精度的影响
                if (Objects.equals(num.compareTo(0.00) ,0)){
                    cost = BasicConstant.ZERO_DOUBLE;
                }
                if (Objects.equals(cost.compareTo(0.00) ,0) && stockFlowBillEntity.getAddTime() > BasicConstant.PRODUCT_COST_OPTIMIZE_DATE){
                    stockFlowBillEntity.setProductCost(singleProductStock);
                }
                finalProductStock.setCost(cost);
            }
            finalProductStock.setNum(num);
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            finalProductStock.setCost(Arith.add(finalProductStock.getCost(), stockFlowBillEntity.getProductCost()));
        }
    }

    /**
     * 计算库存流水信息，用来更新库存产品相关(有批次但不在重算范围内)
     * @param
     */
    private void stockFlowCalculateByBatchTwo(ProductRecalculateDTO finalProductStock, BatchFlowBillEntity batchFlowBill){
        if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.ORI_STOCK.getCode())){
            finalProductStock.setCost(Arith.add(finalProductStock.getCost(), Arith.mul(batchFlowBill.getProductCost(), batchFlowBill.getNum())));
            finalProductStock.setNum(Arith.add(finalProductStock.getNum(), batchFlowBill.getNum()));
        }else if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
            finalProductStock.setCost(Arith.sub(finalProductStock.getCost(), Arith.mul(batchFlowBill.getProductCost(), batchFlowBill.getNum())));
            finalProductStock.setNum(Arith.sub(finalProductStock.getNum(), batchFlowBill.getNum()));
        }else if (Objects.equals(batchFlowBill.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            finalProductStock.setCost(Arith.add(finalProductStock.getCost(), batchFlowBill.getProductCost()));
        }
    }

    /**
     * 计算库存流水信息，用来更新库存产品相关 有批次
     * @param
     */
    private StockFlowBillEntity stockFlowBillCalculateByBatch(ProductRecalculateDTO finalProductStock, StockFlowBillEntity stockFlowBillEntity, StockFlowBillEntity stockFlowBillEntityExt, StockFlowBillEntity oldStockFlowBillEntity, ProductRecalculateDTO finalProductBatch, BatchFlowBillEntity recalculationAtchFlowBill){
        StockFlowBillEntity stockFlowBillEntitys = new StockFlowBillEntity();
        stockFlowBillEntitys.setId(stockFlowBillEntity.getId());
        stockFlowBillEntitys.setStockType(stockFlowBillEntity.getStockType());
        stockFlowBillEntitys.setRefProductId(stockFlowBillEntity.getRefProductId());
        stockFlowBillEntitys.setWarehouseKey(stockFlowBillEntity.getWarehouseKey());
        stockFlowBillEntitys.setNum(stockFlowBillEntity.getNum());
        stockFlowBillEntitys.setBusinessType(stockFlowBillEntity.getBusinessType());
        stockFlowBillEntitys.setProductId(stockFlowBillEntity.getProductId());
        if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ORI_STOCK.getCode())){
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntityExt.getProductCost());
                }else {
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                }
            }else if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    if (Objects.equals(oldStockFlowBillEntity.getProductCost().compareTo(stockFlowBillEntity.getProductCost()), 0)){
                        stockFlowBillEntitys.setProductCost(stockFlowBillEntityExt.getProductCost());
                    }else {
                        stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                    }
                }else {
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                }
            }else {
                stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
            }
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
            }else {
                if (Objects.equals(finalProductBatch.getNum().compareTo(0.00) ,0)){
                    if (Objects.equals(finalProductBatch.getCost().compareTo(0.00), 0)){
                        stockFlowBillEntitys.setProductCost(recalculationAtchFlowBill.getProductCost());
                    }else {
                        stockFlowBillEntitys.setProductCost(0.00);
                    }
                }else if (finalProductBatch.getNum() < 0 && recalculationAtchFlowBill.getRemainingCost() <= 0){
                    stockFlowBillEntitys.setProductCost(0.00);
                }else {
                    stockFlowBillEntitys.setProductCost(Arith.div(finalProductBatch.getCost(), finalProductBatch.getNum()));
                }
            }
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
        }
        stockFlowBillEntitys.setRemainingStock(finalProductStock.getNum());
        stockFlowBillEntitys.setRemainingCost(finalProductStock.getCost());
        return stockFlowBillEntitys;
    }

    /**
     * 计算库存流水信息，用来更新库存产品相关 不需要重算的批次
     * @param
     */
    private StockFlowBillEntity stockFlowBillCalculateByNotBatch(ProductRecalculateDTO finalProductStock, StockFlowBillEntity stockFlowBillEntity, StockFlowBillEntity stockFlowBillEntityExt, StockFlowBillEntity oldStockFlowBillEntity, BatchFlowBillEntity recalculationAtchFlowBill){
        StockFlowBillEntity stockFlowBillEntitys = new StockFlowBillEntity();
        stockFlowBillEntitys.setId(stockFlowBillEntity.getId());
        stockFlowBillEntitys.setStockType(stockFlowBillEntity.getStockType());
        stockFlowBillEntitys.setRefProductId(stockFlowBillEntity.getRefProductId());
        stockFlowBillEntitys.setWarehouseKey(stockFlowBillEntity.getWarehouseKey());
        stockFlowBillEntitys.setNum(stockFlowBillEntity.getNum());
        stockFlowBillEntitys.setBusinessType(stockFlowBillEntity.getBusinessType());
        stockFlowBillEntitys.setProductId(stockFlowBillEntity.getProductId());
        if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ORI_STOCK.getCode())){
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntityExt.getProductCost());
                }else {
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                }
            }else if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    if (Objects.equals(oldStockFlowBillEntity.getProductCost().compareTo(stockFlowBillEntity.getProductCost()), 0)){
                        stockFlowBillEntitys.setProductCost(stockFlowBillEntityExt.getProductCost());
                    }else {
                        stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                    }
                }else {
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                }
            }else {
                stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
            }
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
            }else {
                stockFlowBillEntitys.setProductCost(recalculationAtchFlowBill.getProductCost());
            }
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
        }
        stockFlowBillEntitys.setRemainingStock(finalProductStock.getNum());
        stockFlowBillEntitys.setRemainingCost(finalProductStock.getCost());
        return stockFlowBillEntitys;
    }

    /**
     * 计算库存流水信息，用来更新库存产品相关 无批次
     * @param
     */
    private StockFlowBillEntity stockFlowBillCalculateByStock(ProductRecalculateDTO finalProductStock, StockFlowBillEntity stockFlowBillEntity, StockFlowBillEntity stockFlowBillEntityExt, StockFlowBillEntity oldStockFlowBillEntity){
        StockFlowBillEntity stockFlowBillEntitys = new StockFlowBillEntity();
        stockFlowBillEntitys.setId(stockFlowBillEntity.getId());
        stockFlowBillEntitys.setStockType(stockFlowBillEntity.getStockType());
        stockFlowBillEntitys.setRefProductId(stockFlowBillEntity.getRefProductId());
        stockFlowBillEntitys.setWarehouseKey(stockFlowBillEntity.getWarehouseKey());
        stockFlowBillEntitys.setNum(stockFlowBillEntity.getNum());
        stockFlowBillEntitys.setBusinessType(stockFlowBillEntity.getBusinessType());
        stockFlowBillEntitys.setProductId(stockFlowBillEntity.getProductId());
        if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.IN_STOCK.getCode()) || Objects.equals(stockFlowBillEntity.getStockType() , StockTypeEnum.ORI_STOCK.getCode())){
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.REFUND_INSTOCK.getCode())){
                if (Objects.nonNull(stockFlowBillEntityExt)){
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntityExt.getProductCost());
                }else {
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                }
            } else if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode())) {
                if (Objects.nonNull(stockFlowBillEntityExt)) {
                    if (Objects.equals(oldStockFlowBillEntity.getProductCost().compareTo(stockFlowBillEntity.getProductCost()), 0)) {
                        stockFlowBillEntitys.setProductCost(stockFlowBillEntityExt.getProductCost());
                    } else {
                        stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                    }
                } else {
                    stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                }
            }else {
                stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
            }
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
            if (Objects.equals(stockFlowBillEntity.getBusinessType(), XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
            }else {
                if (Objects.equals(finalProductStock.getNum().compareTo(0.00) ,0)){
                    if (Objects.equals(finalProductStock.getCost().compareTo(0.00), 0)){
                        stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
                    }else {
                        stockFlowBillEntitys.setProductCost(0.00);
                    }
                }else if (finalProductStock.getNum() < 0 && stockFlowBillEntity.getRemainingCost() <= 0){
                    stockFlowBillEntitys.setProductCost(0.00);
                }else {
                    stockFlowBillEntitys.setProductCost(Arith.div(finalProductStock.getCost() , finalProductStock.getNum()));
                }
            }
        }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
            stockFlowBillEntitys.setProductCost(stockFlowBillEntity.getProductCost());
        }
        stockFlowBillEntitys.setRemainingStock(finalProductStock.getNum());
        stockFlowBillEntitys.setRemainingCost(finalProductStock.getCost());
        return stockFlowBillEntitys;
    }

    /**
     * 获得计算map
     * 按warehouseKey进行分组
     */
    private Map<String, List<StockFlowBillEntity>> getStockFlowCalculateMap(JSONArray productArray, List<Long> stockProductId, List<Long> batchProductId, Integer type, Integer isWorkFlow) throws XbbException {
        Map<String, List<StockFlowBillEntity>> stockFlowBillListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i=0; i<productArray.size(); i++){
            JSONObject productObject = productArray.getJSONObject(i);
            Long productId = productObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long warehouseId;
            if (Objects.equals(type , StockTypeEnum.ADJUST_STOCK.getCode())){
                warehouseId = productObject.getJSONArray(SelectProductEnum.WAREHOUSE.getAttr()).getJSONObject(0).getLong("id");
            }else if (Objects.equals(isWorkFlow , BasicConstant.ZERO)){
                Object value = productObject.get(SelectProductEnum.WAREHOUSE.getAttr());
                if (value instanceof String){
                    warehouseId = productObject.getLong(SelectProductEnum.WAREHOUSE.getAttr());
                }else {
                    warehouseId = productObject.getJSONArray(SelectProductEnum.WAREHOUSE.getAttr()).getJSONObject(0).getLong("id");
                }
            }else {
                 warehouseId = productObject.getLong(SelectProductEnum.WAREHOUSE.getAttr());
            }
            Integer enableBatchShelfLife = FastJsonHelper.getIntegerOrDefaultFromFormData(productObject, ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr(), 0);
            //判断产品有无开启批次
            if (Objects.equals(enableBatchShelfLife , 1 ) || (Objects.nonNull(productObject.getString(SelectProductEnum.BATCH.getAttr())) && StringUtils.isNotEmpty(productObject.getString(SelectProductEnum.BATCH.getAttr())))){
                batchProductId.add(productId);
            }
            stockProductId.add(productId);
            String warehouseKey = productId + "_" + warehouseId;
            stockFlowBillListMap.put(warehouseKey, new ArrayList<>());
        }
        return stockFlowBillListMap;
    }

    /**
     * 获得对比list
     * 按最小粒度进行分组
     */
    private List<String> getBatchKeyList(JSONArray productArray, Integer type, Integer isWorkFlow) throws XbbException {
        List<String> batchKeyList = new ArrayList<>();
        for (int i=0; i<productArray.size(); i++){
            JSONObject productObject = productArray.getJSONObject(i);
            Long productId = productObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long warehouseId;
            if (Objects.equals(type , StockTypeEnum.ADJUST_STOCK.getCode())){
                warehouseId = productObject.getJSONArray(SelectProductEnum.WAREHOUSE.getAttr()).getJSONObject(0).getLong("id");
            }else if(Objects.equals(isWorkFlow , BasicConstant.ZERO)){
                Object value = productObject.get(SelectProductEnum.WAREHOUSE.getAttr());
                if (value instanceof String){
                    warehouseId = productObject.getLong(SelectProductEnum.WAREHOUSE.getAttr());
                }else {
                    warehouseId = productObject.getJSONArray(SelectProductEnum.WAREHOUSE.getAttr()).getJSONObject(0).getLong("id");
                }
            }else {
                warehouseId = productObject.getLong(SelectProductEnum.WAREHOUSE.getAttr());
            }
            Integer enableBatchShelfLife = FastJsonHelper.getIntegerOrDefaultFromFormData(productObject, ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr(), 0);
            String batchKey;
            //获取计算过程中的最小粒度
            if (Objects.equals(enableBatchShelfLife , 1 ) || (Objects.nonNull(productObject.getString(SelectProductEnum.BATCH.getAttr())) && StringUtils.isNotEmpty(productObject.getString(SelectProductEnum.BATCH.getAttr())))){
                String batch = FastJsonHelper.getStringOrDefaultFromFormData(productObject, SelectProductEnum.BATCH.getAttr(), "");
                Long produceDate = FastJsonHelper.getLongOrDefaultFromFormData(productObject, SelectProductEnum.PRODUCE_DATE.getAttr(), 0L);
                Long expireDate = FastJsonHelper.getLongOrDefaultFromFormData(productObject, SelectProductEnum.GUARANTEE_PERIOD.getAttr(), 0L);
                Long guaranteePeriod = expireDate * 60*60*24;
                batchKey = BatchKeyHelp.getBatchKey(productId, warehouseId, batch, produceDate, guaranteePeriod);
            }else {
                batchKey = productId + "_" + warehouseId;
            }
            batchKeyList.add(batchKey);
        }
        return batchKeyList;
    }

    /**
     * 对处理完的流水数据进行处理，好更新后续的出入库产品关联表等
     * @param productUpdateRecalculate
     * @param stockFlowBillEntityMap
     * @param batchFlowBillEntityMap
     * @param productstockMap
     * @param productStockBatchMap
     * @param corpid
     * @param productArray
     */
    private void updateDataRecalculate(ProductUpdateRecalculateDTO productUpdateRecalculate, Map<String, StockFlowBillEntity> stockFlowBillEntityMap, Map<String, BatchFlowBillEntity> batchFlowBillEntityMap, Map<String, ProductRecalculateDTO> productstockMap, Map<String, ProductRecalculateDTO> productStockBatchMap, String corpid, JSONArray productArray){
        List<StockFlowBillEntity> stockFlowBillList = productUpdateRecalculate.getStockFlowBillEntityList();
        List<BatchFlowBillEntity> batchFlowBillList = productUpdateRecalculate.getBatchFlowBillEntityList();
        Map<Long, Long> unitMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //开始处理多单位
        for (int i=0; i<productArray.size(); i++){
            JSONObject productJsonObject = productArray.getJSONObject(i);
            if(!Objects.equals(productJsonObject.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getSaasAttr()), 0) && !Objects.equals(productJsonObject.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), 0 )){
                Object value = productJsonObject.get(ProductEnum.UNIT.getAttr());
                if (Objects.nonNull(value) && (value instanceof Integer || value instanceof Long)){
                    unitMap.put(productJsonObject.getLong(ProductEnum.NAME.getAttr()), productJsonObject.getLong(ProductEnum.UNIT.getAttr()));
                }
            }
        }
        List<Long> instockProductIdIn = new ArrayList<>();
        List<Long> outstockProductIdIn = new ArrayList<>();
        stockFlowBillList.forEach(stockFlowBillEntity -> {
            stockFlowBillEntity.setUpdateTime(DateTimeUtil.getInt());
            Long productId = stockFlowBillEntity.getProductId();
            Long productUnit = unitMap.get(productId);
            if (Objects.nonNull(productUnit)){
                if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.IN_STOCK.getCode())){
                    instockProductIdIn.add(stockFlowBillEntity.getRefProductId());
                }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
                    outstockProductIdIn.add(stockFlowBillEntity.getRefProductId());
                }
            }
        });
        batchFlowBillList.forEach(batchFlowBillEntity -> {
            batchFlowBillEntity.setUpdateTime(DateTimeUtil.getInt());
        });
        //获得多单位比例
        List<InstockProductEntity> instockProductList = instockProductModel.getInstockProductById(instockProductIdIn, corpid);
        List<OutstockProductEntity> outstockProductList = outstockProductModel.getOutstockProductById(outstockProductIdIn, corpid);
        Map<Long, Double> instockUnitMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> outstockUnitMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        instockProductList.forEach(instockProductEntity -> {
            instockUnitMap.put(instockProductEntity.getId(), instockProductEntity.getRate());
        });
        outstockProductList.forEach(outstockProductEntity -> {
            outstockUnitMap.put(outstockProductEntity.getId(), outstockProductEntity.getRate());
        });
        //处理出入库关联表需要更新的数据
        stockFlowBillList.forEach(stockFlowBillEntity -> {
            if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.IN_STOCK.getCode())){
                InstockProductEntity instockProductEntity = new InstockProductEntity();
                instockProductEntity.setId(stockFlowBillEntity.getRefProductId());
                instockProductEntity.setCost(stockFlowBillEntity.getProductCost());
                instockProductEntity.setProductNum(stockFlowBillEntity.getNum());
                Integer Type = InstockTypeEnum.getByStockBusinessType(stockFlowBillEntity.getBusinessType()).getCode();
                instockProductEntity.setType(Type);
                if (instockUnitMap.containsKey(stockFlowBillEntity.getRefProductId())){
                    instockProductEntity.setRate(instockUnitMap.get(stockFlowBillEntity.getRefProductId()));
                }
                productUpdateRecalculate.getInstockProductEntityList().add(instockProductEntity);
            }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode())){
                OutstockProductEntity outstockProductEntity = new OutstockProductEntity();
                outstockProductEntity.setId(stockFlowBillEntity.getRefProductId());
                outstockProductEntity.setCost(stockFlowBillEntity.getProductCost());
                outstockProductEntity.setProductNum(stockFlowBillEntity.getNum());
                Integer Type = OutstockTypeEnum.getByStockBusinessType(stockFlowBillEntity.getBusinessType()).getCode();
                outstockProductEntity.setType(Type);
                if (outstockUnitMap.containsKey(stockFlowBillEntity.getRefProductId())){
                    outstockProductEntity.setRate(outstockUnitMap.get(stockFlowBillEntity.getRefProductId()));
                }
                productUpdateRecalculate.getOutstockProductEntityList().add(outstockProductEntity);
                String key = stockFlowBillEntity.getRefProductId() +"_"+ stockFlowBillEntity.getStockType();
                BatchFlowBillEntity batchFlowBillEntity = batchFlowBillEntityMap.get(key);
                List<StockFlowBillEntity> stockFlowBillEntityList = productUpdateRecalculate.getStockFlowListMap().get(stockFlowBillEntity.getWarehouseKey());
                List<BatchFlowBillEntity> batchFlowBillEntityList = null;
                if (Objects.nonNull(batchFlowBillEntity)){
                    batchFlowBillEntityList = productUpdateRecalculate.getBatchFlowListMap().get(batchFlowBillEntity.getBatchKey());
                }
                if (Objects.isNull(stockFlowBillEntityList)){
                    stockFlowBillEntityList = new ArrayList<>();
                }
                if (Objects.isNull(batchFlowBillEntityList)){
                    batchFlowBillEntityList = new ArrayList<>();
                }
                stockFlowBillEntityList.add(stockFlowBillEntity);
                productUpdateRecalculate.getStockFlowListMap().put(stockFlowBillEntity.getWarehouseKey(), stockFlowBillEntityList);
                if (Objects.nonNull(batchFlowBillEntity)){
                    batchFlowBillEntityList.add(batchFlowBillEntity);
                    productUpdateRecalculate.getBatchFlowListMap().put(batchFlowBillEntity.getBatchKey(), batchFlowBillEntityList);
                }
            }else if (Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode())){
                CostAdjustProductEntity costAdjustProductEntity = new CostAdjustProductEntity();
                costAdjustProductEntity.setId(stockFlowBillEntity.getRefProductId());
                costAdjustProductEntity.setCorpid(corpid);
                Long refProductId = stockFlowBillEntity.getRefProductId();
                BatchFlowBillEntity batchFlowBillEntity = batchFlowBillEntityMap.get(refProductId +"_"+ stockFlowBillEntity.getStockType());
                double oldCost, newCost;
                if (Objects.nonNull(batchFlowBillEntity)){
                    if (Objects.equals(batchFlowBillEntity.getRemainingStock().compareTo(0.00) ,0)){
                        oldCost =0.00;
                        newCost =0.00;
                    }else {
                        oldCost = Arith.div(Arith.sub(batchFlowBillEntity.getRemainingCost(), batchFlowBillEntity.getProductCost()) , batchFlowBillEntity.getRemainingStock());
                        newCost = Arith.div(batchFlowBillEntity.getRemainingCost(), batchFlowBillEntity.getRemainingStock());
                    }
                    costAdjustProductEntity.setTotalCost(new BigDecimal(batchFlowBillEntity.getRemainingCost()));
                    costAdjustProductEntity.setOldCost(new BigDecimal(oldCost));
                    costAdjustProductEntity.setNewCost(new BigDecimal(newCost));
                }else {
                    if (Objects.equals(stockFlowBillEntity.getRemainingStock().compareTo(0.00) ,0)){
                        oldCost =0.00;
                        newCost =0.00;
                    }else {
                        oldCost = Arith.div(Arith.sub(stockFlowBillEntity.getRemainingCost(), stockFlowBillEntity.getProductCost()), stockFlowBillEntity.getRemainingStock());
                        newCost = Arith.div(stockFlowBillEntity.getRemainingCost(), stockFlowBillEntity.getRemainingStock());
                    }
                    costAdjustProductEntity.setTotalCost(new BigDecimal(stockFlowBillEntity.getRemainingCost()));
                    costAdjustProductEntity.setOldCost(new BigDecimal(oldCost));
                    costAdjustProductEntity.setNewCost(new BigDecimal(newCost));
                }
                productUpdateRecalculate.getCostAdjustProductEntityList().add(costAdjustProductEntity);
            }
        });
        //处理合同产品关联表需要更新的数据
        List<OutstockProductEntity> outstockProductEntityList = productUpdateRecalculate.getOutstockProductEntityList();
        List<Long> outstockProductId = new ArrayList<>();
        outstockProductEntityList.forEach(outstockProductEntity -> {
            if (Objects.equals(outstockProductEntity.getType(), OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())){
                outstockProductId.add(outstockProductEntity.getId());
            }
        });
        List<OutstockProductEntity> outstockProductEntityLists = outstockProductModel.getOutstockProductById(outstockProductId , corpid);
        outstockProductEntityLists.forEach(outstockProductEntity -> {
            ContractProductEntity contractProductEntity = new ContractProductEntity();
            StockFlowBillEntity stockFlowBillEntity = stockFlowBillEntityMap.get(outstockProductEntity.getId() +"_"+ StockTypeEnum.OUT_STOCK.getCode());
            contractProductEntity.setCost(stockFlowBillEntity.getProductCost());
            contractProductEntity.setId(outstockProductEntity.getRefProductId());
            productUpdateRecalculate.getContractProductEntityList().add(contractProductEntity);
        });
        List<InstockProductEntity> instockProductEntityList = productUpdateRecalculate.getInstockProductEntityList();
        List<Long> instockProductId = new ArrayList<>();
        instockProductEntityList.forEach(instockProductEntity -> {
            if (Objects.equals(instockProductEntity.getType(), InstockTypeEnum.RED_CONTRACT_INSTOCK.getCode())){
                instockProductId.add(instockProductEntity.getId());
            }
        });
        List<InstockProductEntity> instockProductEntities = instockProductModel.getInstockProductById(instockProductId , corpid);
        instockProductEntities.forEach(instockProductEntity -> {
            ContractProductEntity contractProductEntity = new ContractProductEntity();
            StockFlowBillEntity stockFlowBillEntity = stockFlowBillEntityMap.get(instockProductEntity.getId() +"_"+ StockTypeEnum.IN_STOCK.getCode());
            contractProductEntity.setCost(stockFlowBillEntity.getProductCost());
            contractProductEntity.setId(instockProductEntity.getRefProductId());
            productUpdateRecalculate.getContractProductEntityList().add(contractProductEntity);
        });
        //处理分仓表需要更新的数据
        for(String stockKey : productstockMap.keySet()){
            ProductWarehouseEntity productWarehouseEntity = new ProductWarehouseEntity();
            productWarehouseEntity.setWarehouseKey(productstockMap.get(stockKey).getWarehouseKey());
            if (Objects.equals(productstockMap.get(stockKey).getNum().compareTo(0.00) ,0)){
                List<StockFlowBillEntity> stockFlowBillEntityList = productUpdateRecalculate.getStockFlowListMap().get(productstockMap.get(stockKey).getWarehouseKey());
                if (Objects.nonNull(stockFlowBillEntityList)){
                    StockFlowBillEntity stockFlowBillEntity = stockFlowBillEntityList.get(stockFlowBillEntityList.size()-1);
                    productWarehouseEntity.setCost(stockFlowBillEntity.getProductCost());
                }
            }else {
                productWarehouseEntity.setCost(Arith.div(productstockMap.get(stockKey).getCost(), productstockMap.get(stockKey).getNum()));
            }
            ProductRecalculateDTO productRecalculateDTO = productstockMap.get(stockKey);
            productWarehouseEntity.setTotalCost(productRecalculateDTO.getCost());
            productWarehouseEntity.setId(productRecalculateDTO.getWarehouseId());
            productWarehouseEntity.setCorpid(corpid);
            productWarehouseEntity.setProductId(productRecalculateDTO.getProductId());
            productWarehouseEntity.setNum(productRecalculateDTO.getNum());
            productWarehouseEntity.setUpdateTime(DateTimeUtil.getInt());
            productUpdateRecalculate.getProductWarehouseEntityList().add(productWarehouseEntity);
        }
        //处理批次表需要更新的数据
        for(String stockKey : productStockBatchMap.keySet()){
            ProductStockEntity productStockEntity = new ProductStockEntity();
            productStockEntity.setBatchKey(productStockBatchMap.get(stockKey).getBatchKey());
            if (Objects.equals(productStockBatchMap.get(stockKey).getNum().compareTo(0.00) ,0)){
                List<BatchFlowBillEntity> batchFlowBillEntityList = productUpdateRecalculate.getBatchFlowListMap().get(productStockBatchMap.get(stockKey).getBatchKey());
                if (Objects.nonNull(batchFlowBillEntityList)){
                    BatchFlowBillEntity batchFlowBillEntity = batchFlowBillEntityList.get(batchFlowBillEntityList.size()-1);
                    productStockEntity.setCost(batchFlowBillEntity.getProductCost());
                }
            }else {
                productStockEntity.setCost(Arith.div(productStockBatchMap.get(stockKey).getCost() , productStockBatchMap.get(stockKey).getNum()));
            }
            ProductRecalculateDTO productRecalculateDTO = productStockBatchMap.get(stockKey);
            productStockEntity.setTotalCost(productRecalculateDTO.getCost());
            productStockEntity.setNum(productRecalculateDTO.getNum());
            productStockEntity.setProductId(productRecalculateDTO.getProductId());
            productStockEntity.setUpdateTime(DateTimeUtil.getInt());
            productUpdateRecalculate.getProductStockEntityList().add(productStockEntity);
        }
    }

    /**
     *更新各个单据
     */
    private void updateData(ProductUpdateRecalculateDTO productUpdateRecalculate, String corpid) throws XbbException {
        //更新库存流水
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getStockFlowBillEntityList())){
            List<StockFlowBillEntity> stockFlowBillEntityList = productUpdateRecalculate.getStockFlowBillEntityList();
            int pageSize = 100;
            int totalCount = stockFlowBillEntityList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    stockFlowBillModel.updateStockFlowById(stockFlowBillEntityList.subList(start * pageSize, totalCount), corpid);
                    break;
                } else {
                    stockFlowBillModel.updateStockFlowById(stockFlowBillEntityList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        //更新批次流水
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getBatchFlowBillEntityList())){
            List<BatchFlowBillEntity> batchFlowBillEntityList = productUpdateRecalculate.getBatchFlowBillEntityList();
            int pageSize = 100;
            int totalCount = batchFlowBillEntityList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    batchFlowBillModel.updateBatchFlowById(batchFlowBillEntityList.subList(start * pageSize, totalCount), corpid);
                    break;
                } else {
                    batchFlowBillModel.updateBatchFlowById(batchFlowBillEntityList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        //更新出库产品关联表
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getOutstockProductEntityList())){
            List<OutstockProductEntity> outstockProductEntityList = productUpdateRecalculate.getOutstockProductEntityList();
            int pageSize = 100;
            int totalCount = outstockProductEntityList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    outstockProductModel.updateOutstockProductById(outstockProductEntityList.subList(start * pageSize, totalCount), corpid);
                    break;
                } else {
                    outstockProductModel.updateOutstockProductById(outstockProductEntityList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        //更新入库产品关联表
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getInstockProductEntityList())){
            List<InstockProductEntity> instockProductEntityList = productUpdateRecalculate.getInstockProductEntityList();
            int pageSize = 100;
            int totalCount = instockProductEntityList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    instockProductModel.updateInstockProductById(instockProductEntityList.subList(start * pageSize, totalCount), corpid);
                    break;
                } else {
                    instockProductModel.updateInstockProductById(instockProductEntityList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        //更新合同产品关联表
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getContractProductEntityList())){
            List<ContractProductEntity> contractProductEntityList = productUpdateRecalculate.getContractProductEntityList();
            int pageSize = 100;
            int totalCount = contractProductEntityList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    contractProductModel.updateInstockProductById(contractProductEntityList.subList(start * pageSize, totalCount), corpid);
                    break;
                } else {
                    contractProductModel.updateInstockProductById(contractProductEntityList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        //更新成本调整单关联产品表
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getCostAdjustProductEntityList())){
            List<CostAdjustProductEntity> costAdjustProductEntityList = productUpdateRecalculate.getCostAdjustProductEntityList();
            int pageSize = 100;
            int totalCount = costAdjustProductEntityList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    costAdjustProductModel.updateCostProductById(costAdjustProductEntityList.subList(start * pageSize, totalCount), corpid);
                    break;
                } else {
                    costAdjustProductModel.updateCostProductById(costAdjustProductEntityList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        //更新分仓成本与数量
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getProductWarehouseEntityList())){
            List<ProductWarehouseEntity> productWarehouseEntityList = productUpdateRecalculate.getProductWarehouseEntityList();
            int pageSize = 100;
            int totalCount = productWarehouseEntityList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    updateProductWarehouse(productWarehouseEntityList.subList(start * pageSize, totalCount), corpid);
                    break;
                } else {
                    updateProductWarehouse(productWarehouseEntityList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
        //更新批次成本与数量
        if (CollectionsUtil.isNotEmpty(productUpdateRecalculate.getProductStockEntityList())){
            List<ProductStockEntity> productStockList = productUpdateRecalculate.getProductStockEntityList();
            int pageSize = 100;
            int totalCount = productStockList.size();
            int start = 0;
            while (true) {
                if ((start + 1) * pageSize >= totalCount) {
                    updateProductStock(productStockList.subList(start * pageSize, totalCount), corpid);
                    break;
                } else {
                    updateProductStock(productStockList.subList(start * pageSize, (start + 1) * pageSize), corpid);
                }
                start++;
            }
        }
    }

    /**
     * 处理合同数据，并进行更新
     * @param contractProductList
     * @param corpid
     * @throws XbbException
     */
    private void updateContractDate(List<ContractProductEntity> contractProductList, String corpid) throws XbbException {
        if (CollectionsUtil.isEmpty(contractProductList)){
           return;
        }
        List<Long> contractProductId = new ArrayList<>();
        List<Long> contractId = new ArrayList<>();
        List<Long> outstockProductId = new ArrayList<>();
        Map<Long, JSONObject> contractProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> contractIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> refundAndContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, ContractEntityExt> contractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        contractProductList.forEach(contractProductEntity -> {
            contractProductId.add(contractProductEntity.getId());
        });
        //获取成本改变了的合同关联产品
        List<ContractProductEntity> contractProductEntityList = contractProductModel.getById(contractProductId , corpid);
        //获得影响合同的所有关联产品
        contractProductEntityList.forEach(contractProductEntity -> {
            contractId.add(contractProductEntity.getContractId());
        });
        List<ContractProductEntity> contractProductEntityLists = contractProductModel.getContractProductByContractIdIn(corpid , contractId);
        //获得原来的合同信息
        List<ContractEntityExt> contractEntityList = contractModel.findEntitysByIdIn(corpid, 0, contractId);
        contractEntityList.forEach(contractEntityExt -> {
            contractMap.put(contractEntityExt.getId(), contractEntityExt);
        });
        //获得合同关联的销售出库单数据
        List<OutstockProductEntity> outstockProductList = outstockProductModel.getOutstockProductByRefId(contractId, corpid);
        //将合同产品关联表与销售出库单关联表对应起来
        Map<Long, List<OutstockProductEntity>> outstockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        outstockProductList.forEach(outstockProductEntity -> {
            List<OutstockProductEntity> outstockProductEntityList = outstockProductMap.get(outstockProductEntity.getRefProductId());
            if (Objects.isNull(outstockProductEntityList)){
                outstockProductEntityList = new ArrayList<>();
            }
            outstockProductEntityList.add(outstockProductEntity);
            outstockProductMap.put(outstockProductEntity.getRefProductId(), outstockProductEntityList);
        });
        //计算涉及到合同的所有关联表的信息，来获取最新的合同成本
        contractProductEntityLists.forEach(contractProductEntity -> {
            List<OutstockProductEntity> outstockProductEntityList = outstockProductMap.get(contractProductEntity.getId());
            double outProductCost = 0.00;
            if (Objects.nonNull(outstockProductEntityList)){
                for (OutstockProductEntity outstockProductEntity : outstockProductEntityList){
                    double num = Arith.sub(outstockProductEntity.getProductNum(), outstockProductEntity.getInstockNum());
                    outProductCost = Arith.add(outProductCost, Arith.mul(num, outstockProductEntity.getCost()));
                }
            }
            if (contractProductMap.containsKey(contractProductEntity.getContractId())){
                JSONObject productObject = contractProductMap.get(contractProductEntity.getContractId());
                double oldCost = productObject.getDouble("cost");
                double cost = Arith.mul(contractProductEntity.getCost(), Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getOutstockNum()));
                double newCost = Arith.add(oldCost, Arith.add(cost, outProductCost));
                productObject.put("cost", newCost);
                contractProductMap.put(contractProductEntity.getContractId() , productObject);
            }else {
                JSONObject productObject = new JSONObject();
                productObject.put("type", contractProductEntity.getType());
                double cost = Arith.mul(contractProductEntity.getCost(), Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getOutstockNum()));
                double newCost = Arith.add(outProductCost, cost);
                productObject.put("cost", newCost);
                productObject.put("id", contractProductEntity.getContractId());
                contractProductMap.put(contractProductEntity.getContractId(), productObject);
            }
            //将退货退款的信息记录下来
            if (Objects.equals(contractProductEntity.getType(), XbbRefTypeEnum.REFUND.getCode())){
                outstockProductId.add(contractProductEntity.getRefProductId());
                contractIdMap.put(contractProductEntity.getRefProductId(), contractProductEntity.getContractId());
            }
        });
        //建立退货退款与合同的关联关系
        List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.getOutstockProductById(outstockProductId, corpid);
        outstockProductEntityList.forEach(outstockProductEntity -> {
            Long salesContractId = outstockProductEntity.getRefId();
            Long outstockProdcutId = outstockProductEntity.getId();
            Long refundContractId = contractIdMap.get(outstockProdcutId);
            refundAndContractMap.put(refundContractId, salesContractId);
        });
        //开始处理需要更新的数据
        List<Map<String, Object>> updateContractEntity = new ArrayList<>();
        for (Long contractIds : contractProductMap.keySet()){
            Map<String, Object> data = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            JSONObject contractObject = contractProductMap.get(contractIds);
            if (Objects.equals(contractObject.getInteger("type"), XbbRefTypeEnum.CONTRACT.getCode())){
                double refundCost = 0;
                //记录下合同关联的退货退款的成本信息，一个合同可能有多个退货退款。
                for (Long refundId : refundAndContractMap.keySet()){
                    if (Objects.equals(contractObject.getLong("id"), refundAndContractMap.get(refundId))){
                        JSONObject refundData = contractMap.get(refundId).getData();
                        refundCost = Arith.add(refundCost, refundData.getDouble(RefundEnum.RETURN_AMOUNT.getAttr()));
                    }
                }
                /**
                 *记录下最新的成本相关的信息
                 *   合同毛利= 合同金额 – 退货金额 – 合同成本
                 *   合同毛利率 = 合同毛利/合同金额*100%
                 *   现金毛利 = 合同已收款金额 – 合同成本
                 *   现金毛利率 = 现金毛利 / 合同已收款金额
                 */
                JSONObject contractData = contractMap.get(contractIds).getData();
                Double grossProfit = Arith.add(contractData.getDouble(ContractEnum.AMOUNT.getAttr()), Arith.sub(refundCost, contractObject.getDouble("cost")));
                Double otherExpense = FastJsonHelper.getDoubleOrDefault(contractData, ContractEnum.OTHER_EXPENSE.getAttr(), BasicConstant.ZERO_DOUBLE);
                Double newGrossProfit =  Arith.sub(grossProfit, otherExpense);
                data.put(ContractEnum.CONTRACT_COST.getAttr(), Arith.add(contractObject.getDouble("cost"), otherExpense));
                data.put(ContractEnum.GROSS_PROFIT.getAttr(), newGrossProfit);
                if (Objects.equals(contractData.getDouble(ContractEnum.AMOUNT.getAttr()).compareTo(0.00) ,0)){
                    data.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), 0.00);
                }else {
                    data.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), Arith.div(newGrossProfit, contractData.getDouble(ContractEnum.AMOUNT.getAttr())));
                }
                data.put(ContractEnum.CASH_PROFIT.getAttr(), Arith.sub(contractData.getDouble(ContractEnum.FINISH_AMOUNT.getAttr()), contractObject.getDouble("cost")));
                if (Objects.equals(contractData.getDouble(ContractEnum.FINISH_AMOUNT.getAttr()).compareTo(0.00) ,0)){
                    data.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), 0.00);
                }else {
                    data.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), Arith.div((Double) data.get(ContractEnum.CASH_PROFIT.getAttr()), contractData.getDouble(ContractEnum.FINISH_AMOUNT.getAttr())));
                }
                data.put("id", contractIds);
                updateContractEntity.add(data);
            }
        }
        //开始更新合同数据
        int pageSize = 100;
        int totalCount = updateContractEntity.size();
        int start = 0;
        while (true) {
            if ((start + 1) * pageSize >= totalCount) {
                contractService.updateContractDate(updateContractEntity.subList(start * pageSize, totalCount), corpid);
                break;
            }else {
                contractService.updateContractDate(updateContractEntity.subList(start * pageSize, (start + 1) * pageSize), corpid);
            }
            start++;
        }
    }

    private void updateOldDateByDelete(Map<Long, List<StockFlowBillEntity>> stockFlowBillListMap, List<BatchFlowBillEntity> batchFlowBillEntityList, ProductUpdateRecalculateDTO productUpdateRecalculate){
        List<ProductWarehouseEntity> productWarehouseEntityList = productUpdateRecalculate.getProductWarehouseEntityList();
        List<ProductStockEntity> productStockEntityList = productUpdateRecalculate.getProductStockEntityList();
        Map<Long, List<BatchFlowBillEntity>> batchFlowBillListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        batchFlowBillEntityList.forEach(batchFlowBillEntity -> {
            batchFlowBillEntity.setUpdateTime(DateTimeUtil.getInt());
            if (Objects.equals(batchFlowBillEntity.getDel(), 0)){
                List<BatchFlowBillEntity> batchFlowBillList = batchFlowBillListMap.get(batchFlowBillEntity.getProductId());
                if (Objects.isNull(batchFlowBillList)){
                    batchFlowBillList= new ArrayList<>();
                }
                batchFlowBillList.add(batchFlowBillEntity);
                batchFlowBillListMap.put(batchFlowBillEntity.getProductId(),batchFlowBillList);
            }
        });
        if (CollectionsUtil.isNotEmpty(productWarehouseEntityList)){
            productWarehouseEntityList.forEach(productWarehouseEntity -> {
                Double cost = productWarehouseEntity.getCost();
                if (Objects.isNull(cost)){
                    List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(productWarehouseEntity.getProductId());
                    stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                        if ((Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode()) || Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode()))
                                && Objects.equals(stockFlowBillEntity.getWarehouseKey(), productWarehouseEntity.getWarehouseKey())
                                && Objects.equals(stockFlowBillEntity.getDel(), 0)){
                            productWarehouseEntity.setCost(stockFlowBillEntity.getProductCost());
                        }
                    });
                }
            });
        }
        if (CollectionsUtil.isNotEmpty(productStockEntityList)){
            productStockEntityList.forEach(productStockEntity -> {
                Double cost = productStockEntity.getCost();
                if (Objects.isNull(cost)){
                    List<BatchFlowBillEntity> batchFlowBillEntityLists = batchFlowBillListMap.get(productStockEntity.getProductId());
                    batchFlowBillEntityLists.forEach(batchFlowBillEntity -> {
                        if ((Objects.equals(batchFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode()) || Objects.equals(batchFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode()))
                                && Objects.equals(batchFlowBillEntity.getBatchKey(), productStockEntity.getBatchKey())
                                && Objects.equals(batchFlowBillEntity.getDel(), 0)){
                            productStockEntity.setCost(batchFlowBillEntity.getProductCost());
                        }
                    });
                }
            });
        }
    }

    private void updateOldDateByAdd(Map<String, List<StockFlowBillEntity>> stockFlowBillListMap, List<BatchFlowBillEntity> batchFlowBillEntityList, ProductUpdateRecalculateDTO productUpdateRecalculate){
        List<ProductWarehouseEntity> productWarehouseEntityList = productUpdateRecalculate.getProductWarehouseEntityList();
        List<ProductStockEntity> productStockEntityList = productUpdateRecalculate.getProductStockEntityList();
        Map<Long, List<BatchFlowBillEntity>> batchFlowBillListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        batchFlowBillEntityList.forEach(batchFlowBillEntity -> {
            batchFlowBillEntity.setUpdateTime(DateTimeUtil.getInt());
            if (Objects.equals(batchFlowBillEntity.getDel(), 0)){
                List<BatchFlowBillEntity> batchFlowBillList = batchFlowBillListMap.get(batchFlowBillEntity.getProductId());
                if (Objects.isNull(batchFlowBillList)){
                    batchFlowBillList= new ArrayList<>();
                }
                batchFlowBillList.add(batchFlowBillEntity);
                batchFlowBillListMap.put(batchFlowBillEntity.getProductId(),batchFlowBillList);
            }
        });
        if (CollectionsUtil.isNotEmpty(productWarehouseEntityList)){
            productWarehouseEntityList.forEach(productWarehouseEntity -> {
                Double cost = productWarehouseEntity.getCost();
                if (Objects.isNull(cost)){
                    List<StockFlowBillEntity> stockFlowBillEntityList = stockFlowBillListMap.get(productWarehouseEntity.getWarehouseKey());
                    stockFlowBillEntityList.forEach(stockFlowBillEntity -> {
                        if ((Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode()) || Objects.equals(stockFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode()))
                                && Objects.equals(stockFlowBillEntity.getDel(), 0)){
                            productWarehouseEntity.setCost(stockFlowBillEntity.getProductCost());
                        }
                    });
                }
            });
        }
        if (CollectionsUtil.isNotEmpty(productStockEntityList)){
            productStockEntityList.forEach(productStockEntity -> {
                Double cost = productStockEntity.getCost();
                if (Objects.isNull(cost)){
                    List<BatchFlowBillEntity> batchFlowBillEntityLists = batchFlowBillListMap.get(productStockEntity.getProductId());
                    batchFlowBillEntityLists.forEach(batchFlowBillEntity -> {
                        if ((Objects.equals(batchFlowBillEntity.getStockType(), StockTypeEnum.OUT_STOCK.getCode()) || Objects.equals(batchFlowBillEntity.getStockType(), StockTypeEnum.ADJUST_STOCK.getCode()))
                                && Objects.equals(batchFlowBillEntity.getBatchKey(), productStockEntity.getBatchKey())
                                && Objects.equals(batchFlowBillEntity.getDel(), 0)){
                            productStockEntity.setCost(batchFlowBillEntity.getProductCost());
                        }
                    });
                }
            });
        }
    }

    public void updateProductWarehouse(List<ProductWarehouseEntity> productWarehouseEntityList, String corpid) throws XbbException {
        //更新数据库
        productWarehouseModel.updateProductWarehouseById(productWarehouseEntityList, corpid);
        //根据仓库id和产品id获取分仓表id
        List<String> warehouseKeyList = new ArrayList<>();
        Map<String, Long> warehouseKeyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        productWarehouseEntityList.forEach(productWarehouseEntity -> {
            warehouseKeyList.add(productWarehouseEntity.getWarehouseKey());
        });
        List<ProductWarehouseEntity> productWarehouseList = productWarehouseModel.listByProductIdInWasehouseIn(corpid, warehouseKeyList);
        productWarehouseList.forEach(productWarehouseEntity -> {
            warehouseKeyMap.put(productWarehouseEntity.getWarehouseKey(), productWarehouseEntity.getId());
        });
        //更新ES
        List<InsertDTO> updateDTOList = new ArrayList<>();
        productWarehouseEntityList.forEach(productWarehouseEntity -> {
            Long productWarehouseId = warehouseKeyMap.get(productWarehouseEntity.getWarehouseKey());
            Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            JSONObject object = new JSONObject();
            object.put(ProductWarehouseSubFormEnum.COST.getDataAttr(), productWarehouseEntity.getCost());
            object.put(ProductWarehouseSubFormEnum.TOTAL_COST.getDataAttr(), productWarehouseEntity.getTotalCost());
            object.put(ProductWarehouseSubFormEnum.NUM.getDataAttr(), productWarehouseEntity.getNum());
            map.put(StringConstant.JSON_DATA, object);
            InsertDTO insertDTO = new InsertDTO();
            insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
            insertDTO.setEsId(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE.getType() + "_" + productWarehouseEntity.getCorpid() + "_" + productWarehouseId);
            insertDTO.setParent(productWarehouseEntity.getCorpid() + "_" + productWarehouseEntity.getProductId());
            insertDTO.setSource(map);
            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE);
            updateDTOList.add(insertDTO);
        });
        paasEsModel.updateBatch(updateDTOList, WriteRequest.RefreshPolicy.NONE);
    }

    public void updateProductStock(List<ProductStockEntity> productStockList, String corpid) throws XbbException {
        //更新数据库
        productStockModel.updateProductStockById(productStockList, corpid);
        //更新ES
        Set<String> batchKeyList = new HashSet<>();
        productStockList.forEach(productStockEntity -> {
            batchKeyList.add(productStockEntity.getBatchKey());
        });
        Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.CORPID,corpid);
        param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
        param.put("batchKeyIn",batchKeyList);
        List<ProductStockEntity> productStockEntityList = productStockModel.findEntitysForUpdate(param);
        if (!productStockEntityList.isEmpty()){
            List<InsertDTO> updateBatchList = new ArrayList<>();
            for (ProductStockEntity entity : productStockEntityList) {
                Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                JSONObject object = new JSONObject();
                object.put(ProductStockSubFormEnum.NUM.getDataAttr(),entity.getNum());
                object.put(ProductStockSubFormEnum.COST.getDataAttr(),entity.getCost());
                object.put(ProductStockSubFormEnum.TOTAL_COST.getDataAttr(), entity.getTotalCost());
                map.put(StringConstant.JSON_DATA, object);
                InsertDTO insertDTO = new InsertDTO();
                insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
                insertDTO.setEsId(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO.getType() + "_" + entity.getCorpid() + "_" + entity.getId());
                insertDTO.setParent(entity.getCorpid() + "_" + entity.getProductId());
                insertDTO.setSource(map);
                insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO);
                updateBatchList.add(insertDTO);
            }
            paasEsModel.updateBatch(updateBatchList, WriteRequest.RefreshPolicy.NONE);
        }
    }
}